1 #if defined( _MSC_VER )
2 	#if !defined( _CRT_SECURE_NO_WARNINGS )
3 		#define _CRT_SECURE_NO_WARNINGS		// This test file is not intended to be secure.
4 	#endif
5 #endif
6 
7 #include "tinyxml2.h"
8 #include <cerrno>
9 #include <cstdlib>
10 #include <cstring>
11 #include <ctime>
12 
13 #if defined( _MSC_VER ) || defined (WIN32)
14 	#include <crtdbg.h>
15 	#define WIN32_LEAN_AND_MEAN
16 	#include <windows.h>
17 	_CrtMemState startMemState;
18 	_CrtMemState endMemState;
19 #else
20 	#include <sys/stat.h>
21 	#include <sys/types.h>
22 #endif
23 
24 using namespace tinyxml2;
25 using namespace std;
26 int gPass = 0;
27 int gFail = 0;
28 
29 
XMLTest(const char * testString,const char * expected,const char * found,bool echo=true,bool extraNL=false)30 bool XMLTest (const char* testString, const char* expected, const char* found, bool echo=true, bool extraNL=false )
31 {
32 	bool pass;
33 	if ( !expected && !found )
34 		pass = true;
35 	else if ( !expected || !found )
36 		pass = false;
37 	else
38 		pass = !strcmp( expected, found );
39 	if ( pass )
40 		printf ("[pass]");
41 	else
42 		printf ("[fail]");
43 
44 	if ( !echo ) {
45 		printf (" %s\n", testString);
46 	}
47 	else {
48 		if ( extraNL ) {
49 			printf( " %s\n", testString );
50 			printf( "%s\n", expected );
51 			printf( "%s\n", found );
52 		}
53 		else {
54 			printf (" %s [%s][%s]\n", testString, expected, found);
55 		}
56 	}
57 
58 	if ( pass )
59 		++gPass;
60 	else
61 		++gFail;
62 	return pass;
63 }
64 
XMLTest(const char * testString,XMLError expected,XMLError found,bool echo=true,bool extraNL=false)65 bool XMLTest(const char* testString, XMLError expected, XMLError found, bool echo = true, bool extraNL = false)
66 {
67     return XMLTest(testString, XMLDocument::ErrorIDToName(expected), XMLDocument::ErrorIDToName(found), echo, extraNL);
68 }
69 
XMLTest(const char * testString,bool expected,bool found,bool echo=true,bool extraNL=false)70 bool XMLTest(const char* testString, bool expected, bool found, bool echo = true, bool extraNL = false)
71 {
72     return XMLTest(testString, expected ? "true" : "false", found ? "true" : "false", echo, extraNL);
73 }
74 
XMLTest(const char * testString,T expected,T found,bool echo=true)75 template< class T > bool XMLTest( const char* testString, T expected, T found, bool echo=true )
76 {
77 	bool pass = ( expected == found );
78 	if ( pass )
79 		printf ("[pass]");
80 	else
81 		printf ("[fail]");
82 
83 	if ( !echo )
84 		printf (" %s\n", testString);
85 	else {
86 		char expectedAsString[64];
87 		XMLUtil::ToStr(expected, expectedAsString, sizeof(expectedAsString));
88 
89 		char foundAsString[64];
90 		XMLUtil::ToStr(found, foundAsString, sizeof(foundAsString));
91 
92 		printf (" %s [%s][%s]\n", testString, expectedAsString, foundAsString );
93 	}
94 
95 	if ( pass )
96 		++gPass;
97 	else
98 		++gFail;
99 	return pass;
100 }
101 
102 
NullLineEndings(char * p)103 void NullLineEndings( char* p )
104 {
105 	while( p && *p ) {
106 		if ( *p == '\n' || *p == '\r' ) {
107 			*p = 0;
108 			return;
109 		}
110 		++p;
111 	}
112 }
113 
114 
example_1()115 int example_1()
116 {
117 	XMLDocument doc;
118 	doc.LoadFile( "resources/dream.xml" );
119 
120 	return doc.ErrorID();
121 }
122 /** @page Example_1 Load an XML File
123  *  @dontinclude ./xmltest.cpp
124  *  Basic XML file loading.
125  *  The basic syntax to load an XML file from
126  *  disk and check for an error. (ErrorID()
127  *  will return 0 for no error.)
128  *  @skip example_1()
129  *  @until }
130  */
131 
132 
example_2()133 int example_2()
134 {
135 	static const char* xml = "<element/>";
136 	XMLDocument doc;
137 	doc.Parse( xml );
138 
139 	return doc.ErrorID();
140 }
141 /** @page Example_2 Parse an XML from char buffer
142  *  @dontinclude ./xmltest.cpp
143  *  Basic XML string parsing.
144  *  The basic syntax to parse an XML for
145  *  a char* and check for an error. (ErrorID()
146  *  will return 0 for no error.)
147  *  @skip example_2()
148  *  @until }
149  */
150 
151 
example_3()152 int example_3()
153 {
154 	static const char* xml =
155 		"<?xml version=\"1.0\"?>"
156 		"<!DOCTYPE PLAY SYSTEM \"play.dtd\">"
157 		"<PLAY>"
158 		"<TITLE>A Midsummer Night's Dream</TITLE>"
159 		"</PLAY>";
160 
161 	XMLDocument doc;
162 	doc.Parse( xml );
163 
164 	XMLElement* titleElement = doc.FirstChildElement( "PLAY" )->FirstChildElement( "TITLE" );
165 	const char* title = titleElement->GetText();
166 	printf( "Name of play (1): %s\n", title );
167 
168 	XMLText* textNode = titleElement->FirstChild()->ToText();
169 	title = textNode->Value();
170 	printf( "Name of play (2): %s\n", title );
171 
172 	return doc.ErrorID();
173 }
174 /** @page Example_3 Get information out of XML
175 	@dontinclude ./xmltest.cpp
176 	In this example, we navigate a simple XML
177 	file, and read some interesting text. Note
178 	that this example doesn't use error
179 	checking; working code should check for null
180 	pointers when walking an XML tree, or use
181 	XMLHandle.
182 
183 	(The XML is an excerpt from "dream.xml").
184 
185 	@skip example_3()
186 	@until </PLAY>";
187 
188 	The structure of the XML file is:
189 
190 	<ul>
191 		<li>(declaration)</li>
192 		<li>(dtd stuff)</li>
193 		<li>Element "PLAY"</li>
194 		<ul>
195 			<li>Element "TITLE"</li>
196 			<ul>
197 			    <li>Text "A Midsummer Night's Dream"</li>
198 			</ul>
199 		</ul>
200 	</ul>
201 
202 	For this example, we want to print out the
203 	title of the play. The text of the title (what
204 	we want) is child of the "TITLE" element which
205 	is a child of the "PLAY" element.
206 
207 	We want to skip the declaration and dtd, so the
208 	method FirstChildElement() is a good choice. The
209 	FirstChildElement() of the Document is the "PLAY"
210 	Element, the FirstChildElement() of the "PLAY" Element
211 	is the "TITLE" Element.
212 
213 	@until ( "TITLE" );
214 
215 	We can then use the convenience function GetText()
216 	to get the title of the play.
217 
218 	@until title );
219 
220 	Text is just another Node in the XML DOM. And in
221 	fact you should be a little cautious with it, as
222 	text nodes can contain elements.
223 
224 	@verbatim
225 	Consider: A Midsummer Night's <b>Dream</b>
226 	@endverbatim
227 
228 	It is more correct to actually query the Text Node
229 	if in doubt:
230 
231 	@until title );
232 
233 	Noting that here we use FirstChild() since we are
234 	looking for XMLText, not an element, and ToText()
235 	is a cast from a Node to a XMLText.
236 */
237 
238 
example_4()239 bool example_4()
240 {
241 	static const char* xml =
242 		"<information>"
243 		"	<attributeApproach v='2' />"
244 		"	<textApproach>"
245 		"		<v>2</v>"
246 		"	</textApproach>"
247 		"</information>";
248 
249 	XMLDocument doc;
250 	doc.Parse( xml );
251 
252 	int v0 = 0;
253 	int v1 = 0;
254 
255 	XMLElement* attributeApproachElement = doc.FirstChildElement()->FirstChildElement( "attributeApproach" );
256 	attributeApproachElement->QueryIntAttribute( "v", &v0 );
257 
258 	XMLElement* textApproachElement = doc.FirstChildElement()->FirstChildElement( "textApproach" );
259 	textApproachElement->FirstChildElement( "v" )->QueryIntText( &v1 );
260 
261 	printf( "Both values are the same: %d and %d\n", v0, v1 );
262 
263 	return !doc.Error() && ( v0 == v1 );
264 }
265 /** @page Example_4 Read attributes and text information.
266 	@dontinclude ./xmltest.cpp
267 
268 	There are fundamentally 2 ways of writing a key-value
269 	pair into an XML file. (Something that's always annoyed
270 	me about XML.) Either by using attributes, or by writing
271 	the key name into an element and the value into
272 	the text node wrapped by the element. Both approaches
273 	are illustrated in this example, which shows two ways
274 	to encode the value "2" into the key "v":
275 
276 	@skip example_4()
277 	@until "</information>";
278 
279 	TinyXML-2 has accessors for both approaches.
280 
281 	When using an attribute, you navigate to the XMLElement
282 	with that attribute and use the QueryIntAttribute()
283 	group of methods. (Also QueryFloatAttribute(), etc.)
284 
285 	@skip XMLElement* attributeApproachElement
286 	@until &v0 );
287 
288 	When using the text approach, you need to navigate
289 	down one more step to the XMLElement that contains
290 	the text. Note the extra FirstChildElement( "v" )
291 	in the code below. The value of the text can then
292 	be safely queried with the QueryIntText() group
293 	of methods. (Also QueryFloatText(), etc.)
294 
295 	@skip XMLElement* textApproachElement
296 	@until &v1 );
297 */
298 
299 
main(int argc,const char ** argv)300 int main( int argc, const char ** argv )
301 {
302 	#if defined( _MSC_VER ) && defined( TINYXML2_DEBUG )
303 		_CrtMemCheckpoint( &startMemState );
304 		// Enable MS Visual C++ debug heap memory leaks dump on exit
305 		_CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
306 		{
307 			int leaksOnStart = _CrtDumpMemoryLeaks();
308 			XMLTest( "No leaks on start?", FALSE, leaksOnStart );
309 		}
310 	#endif
311 
312 	{
313 		TIXMLASSERT( true );
314 	}
315 
316 	if ( argc > 1 ) {
317 		XMLDocument* doc = new XMLDocument();
318 		clock_t startTime = clock();
319 		doc->LoadFile( argv[1] );
320  		clock_t loadTime = clock();
321 		int errorID = doc->ErrorID();
322 		delete doc; doc = 0;
323  		clock_t deleteTime = clock();
324 
325 		printf( "Test file '%s' loaded. ErrorID=%d\n", argv[1], errorID );
326 		if ( !errorID ) {
327 			printf( "Load time=%u\n",   (unsigned)(loadTime - startTime) );
328 			printf( "Delete time=%u\n", (unsigned)(deleteTime - loadTime) );
329 			printf( "Total time=%u\n",  (unsigned)(deleteTime - startTime) );
330 		}
331 		exit(0);
332 	}
333 
334 	FILE* fp = fopen( "resources/dream.xml", "r" );
335 	if ( !fp ) {
336 		printf( "Error opening test file 'dream.xml'.\n"
337 				"Is your working directory the same as where \n"
338 				"the xmltest.cpp and dream.xml file are?\n\n"
339 	#if defined( _MSC_VER )
340 				"In windows Visual Studio you may need to set\n"
341 				"Properties->Debugging->Working Directory to '..'\n"
342 	#endif
343 			  );
344 		exit( 1 );
345 	}
346 	fclose( fp );
347 
348 	XMLTest( "Example_1", 0, example_1() );
349 	XMLTest( "Example_2", 0, example_2() );
350 	XMLTest( "Example_3", 0, example_3() );
351 	XMLTest( "Example_4", true, example_4() );
352 
353 	/* ------ Example 2: Lookup information. ---- */
354 
355 	{
356 		static const char* test[] = {	"<element />",
357 										"<element></element>",
358 										"<element><subelement/></element>",
359 										"<element><subelement></subelement></element>",
360 										"<element><subelement><subsub/></subelement></element>",
361 										"<!--comment beside elements--><element><subelement></subelement></element>",
362 										"<!--comment beside elements, this time with spaces-->  \n <element>  <subelement> \n </subelement> </element>",
363 										"<element attrib1='foo' attrib2=\"bar\" ></element>",
364 										"<element attrib1='foo' attrib2=\"bar\" ><subelement attrib3='yeehaa' /></element>",
365 										"<element>Text inside element.</element>",
366 										"<element><b></b></element>",
367 										"<element>Text inside and <b>bolded</b> in the element.</element>",
368 										"<outer><element>Text inside and <b>bolded</b> in the element.</element></outer>",
369 										"<element>This &amp; That.</element>",
370 										"<element attrib='This&lt;That' />",
371 										0
372 		};
373 		for( int i=0; test[i]; ++i ) {
374 			XMLDocument doc;
375 			doc.Parse( test[i] );
376 			XMLTest( "Element test", false, doc.Error() );
377 			doc.Print();
378 			printf( "----------------------------------------------\n" );
379 		}
380 	}
381 #if 1
382 	{
383 		static const char* test = "<!--hello world\n"
384 								  "          line 2\r"
385 								  "          line 3\r\n"
386 								  "          line 4\n\r"
387 								  "          line 5\r-->";
388 
389 		XMLDocument doc;
390 		doc.Parse( test );
391 		XMLTest( "Hello world declaration", false, doc.Error() );
392 		doc.Print();
393 	}
394 
395 	{
396 		// This test is pre-test for the next one
397 		// (where Element1 is inserted "after itself".
398 		// This code didn't use to crash.
399 		XMLDocument doc;
400 		XMLElement* element1 = doc.NewElement("Element1");
401 		XMLElement* element2 = doc.NewElement("Element2");
402 		doc.InsertEndChild(element1);
403 		doc.InsertEndChild(element2);
404 		doc.InsertAfterChild(element2, element2);
405 		doc.InsertAfterChild(element2, element2);
406 	}
407 
408 	{
409 		XMLDocument doc;
410 		XMLElement* element1 = doc.NewElement("Element1");
411 		XMLElement* element2 = doc.NewElement("Element2");
412 		doc.InsertEndChild(element1);
413 		doc.InsertEndChild(element2);
414 
415 		// This insertion "after itself"
416 		// used to cause invalid memory access and crash
417 		doc.InsertAfterChild(element1, element1);
418 		doc.InsertAfterChild(element1, element1);
419 		doc.InsertAfterChild(element2, element2);
420 		doc.InsertAfterChild(element2, element2);
421 	}
422 
423 	{
424 		static const char* test = "<element>Text before.</element>";
425 		XMLDocument doc;
426 		doc.Parse( test );
427 		XMLTest( "Element text before", false, doc.Error() );
428 		XMLElement* root = doc.FirstChildElement();
429 		XMLElement* newElement = doc.NewElement( "Subelement" );
430 		root->InsertEndChild( newElement );
431 		doc.Print();
432 	}
433 	{
434 		XMLDocument* doc = new XMLDocument();
435 		static const char* test = "<element><sub/></element>";
436 		doc->Parse( test );
437 		XMLTest( "Element with sub element", false, doc->Error() );
438 		delete doc;
439 	}
440 	{
441 		// Test: Programmatic DOM nodes insertion return values
442 		XMLDocument doc;
443 
444 		XMLNode* first = doc.NewElement( "firstElement" );
445 		XMLTest( "New element", true, first != 0 );
446 		XMLNode* firstAfterInsertion = doc.InsertFirstChild( first );
447 		XMLTest( "New element inserted first", true, firstAfterInsertion == first );
448 
449 		XMLNode* last = doc.NewElement( "lastElement" );
450 		XMLTest( "New element", true, last != 0 );
451 		XMLNode* lastAfterInsertion = doc.InsertEndChild( last );
452 		XMLTest( "New element inserted last", true, lastAfterInsertion == last );
453 
454 		XMLNode* middle = doc.NewElement( "middleElement" );
455 		XMLTest( "New element", true, middle != 0 );
456 		XMLNode* middleAfterInsertion = doc.InsertAfterChild( first, middle );
457 		XMLTest( "New element inserted middle", true, middleAfterInsertion == middle );
458 	}
459 	{
460 		// Test: Programmatic DOM
461 		// Build:
462 		//		<element>
463 		//			<!--comment-->
464 		//			<sub attrib="0" />
465 		//			<sub attrib="1" />
466 		//			<sub attrib="2" >& Text!</sub>
467 		//		<element>
468 
469 		XMLDocument* doc = new XMLDocument();
470 		XMLNode* element = doc->InsertEndChild( doc->NewElement( "element" ) );
471 
472 		XMLElement* sub[3] = { doc->NewElement( "sub" ), doc->NewElement( "sub" ), doc->NewElement( "sub" ) };
473 		for( int i=0; i<3; ++i ) {
474 			sub[i]->SetAttribute( "attrib", i );
475 		}
476 		element->InsertEndChild( sub[2] );
477 
478 		const int dummyInitialValue = 1000;
479 		int dummyValue = dummyInitialValue;
480 
481 		XMLNode* comment = element->InsertFirstChild( doc->NewComment( "comment" ) );
482 		comment->SetUserData(&dummyValue);
483 		element->InsertAfterChild( comment, sub[0] );
484 		element->InsertAfterChild( sub[0], sub[1] );
485 		sub[2]->InsertFirstChild( doc->NewText( "& Text!" ));
486 		doc->Print();
487 		XMLTest( "Programmatic DOM", "comment", doc->FirstChildElement( "element" )->FirstChild()->Value() );
488 		XMLTest( "Programmatic DOM", "0", doc->FirstChildElement( "element" )->FirstChildElement()->Attribute( "attrib" ) );
489 		XMLTest( "Programmatic DOM", 2, doc->FirstChildElement()->LastChildElement( "sub" )->IntAttribute( "attrib" ) );
490 		XMLTest( "Programmatic DOM", "& Text!",
491 				 doc->FirstChildElement()->LastChildElement( "sub" )->FirstChild()->ToText()->Value() );
492 		XMLTest("User data - pointer", true, &dummyValue == comment->GetUserData(), false);
493 		XMLTest("User data - value behind pointer", dummyInitialValue, dummyValue, false);
494 
495 		// And now deletion:
496 		element->DeleteChild( sub[2] );
497 		doc->DeleteNode( comment );
498 
499 		element->FirstChildElement()->SetAttribute( "attrib", true );
500 		element->LastChildElement()->DeleteAttribute( "attrib" );
501 
502 		XMLTest( "Programmatic DOM", true, doc->FirstChildElement()->FirstChildElement()->BoolAttribute( "attrib" ) );
503 		const int defaultIntValue = 10;
504 		const int replacementIntValue = 20;
505 		int value1 = defaultIntValue;
506 		int value2 = doc->FirstChildElement()->LastChildElement()->IntAttribute( "attrib", replacementIntValue );
507 		XMLError result = doc->FirstChildElement()->LastChildElement()->QueryIntAttribute( "attrib", &value1 );
508 		XMLTest( "Programmatic DOM", XML_NO_ATTRIBUTE, result );
509 		XMLTest( "Programmatic DOM", defaultIntValue, value1 );
510 		XMLTest( "Programmatic DOM", replacementIntValue, value2 );
511 
512 		doc->Print();
513 
514 		{
515 			XMLPrinter streamer;
516 			doc->Print( &streamer );
517 			printf( "%s", streamer.CStr() );
518 		}
519 		{
520 			XMLPrinter streamer( 0, true );
521 			doc->Print( &streamer );
522 			XMLTest( "Compact mode", "<element><sub attrib=\"true\"/><sub/></element>", streamer.CStr(), false );
523 		}
524 		doc->SaveFile( "./resources/out/pretty.xml" );
525 		XMLTest( "Save pretty.xml", false, doc->Error() );
526 		doc->SaveFile( "./resources/out/compact.xml", true );
527 		XMLTest( "Save compact.xml", false, doc->Error() );
528 		delete doc;
529 	}
530 	{
531 		// Test: Dream
532 		// XML1 : 1,187,569 bytes	in 31,209 allocations
533 		// XML2 :   469,073	bytes	in    323 allocations
534 		//int newStart = gNew;
535 		XMLDocument doc;
536 		doc.LoadFile( "resources/dream.xml" );
537 		XMLTest( "Load dream.xml", false, doc.Error() );
538 
539 		doc.SaveFile( "resources/out/dreamout.xml" );
540 		XMLTest( "Save dreamout.xml", false, doc.Error() );
541 		doc.PrintError();
542 
543 		XMLTest( "Dream", "xml version=\"1.0\"",
544 						  doc.FirstChild()->ToDeclaration()->Value() );
545 		XMLTest( "Dream", true, doc.FirstChild()->NextSibling()->ToUnknown() != 0 );
546 		XMLTest( "Dream", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
547 						  doc.FirstChild()->NextSibling()->ToUnknown()->Value() );
548 		XMLTest( "Dream", "And Robin shall restore amends.",
549 						  doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
550 		XMLTest( "Dream", "And Robin shall restore amends.",
551 						  doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
552 
553 		XMLDocument doc2;
554 		doc2.LoadFile( "resources/out/dreamout.xml" );
555 		XMLTest( "Load dreamout.xml", false, doc2.Error() );
556 		XMLTest( "Dream-out", "xml version=\"1.0\"",
557 						  doc2.FirstChild()->ToDeclaration()->Value() );
558 		XMLTest( "Dream-out", true, doc2.FirstChild()->NextSibling()->ToUnknown() != 0 );
559 		XMLTest( "Dream-out", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
560 						  doc2.FirstChild()->NextSibling()->ToUnknown()->Value() );
561 		XMLTest( "Dream-out", "And Robin shall restore amends.",
562 						  doc2.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
563 
564 		//gNewTotal = gNew - newStart;
565 	}
566 
567 
568 	{
569 		const char* error =	"<?xml version=\"1.0\" standalone=\"no\" ?>\n"
570 							"<passages count=\"006\" formatversion=\"20020620\">\n"
571 							"    <wrong error>\n"
572 							"</passages>";
573 
574 		XMLDocument doc;
575 		doc.Parse( error );
576 		XMLTest( "Bad XML", XML_ERROR_PARSING_ATTRIBUTE, doc.ErrorID() );
577 		const char* errorStr = doc.ErrorStr();
578 		XMLTest("Formatted error string",
579 			"Error=XML_ERROR_PARSING_ATTRIBUTE ErrorID=7 (0x7) Line number=3: XMLElement name=wrong",
580 			errorStr);
581 	}
582 
583 	{
584 		const char* str = "<doc attr0='1' attr1='2.0' attr2='foo' />";
585 
586 		XMLDocument doc;
587 		doc.Parse( str );
588 		XMLTest( "Top level attributes", false, doc.Error() );
589 
590 		XMLElement* ele = doc.FirstChildElement();
591 
592 		int iVal;
593 		XMLError result;
594 		double dVal;
595 
596 		result = ele->QueryDoubleAttribute( "attr0", &dVal );
597 		XMLTest( "Query attribute: int as double", XML_SUCCESS, result);
598 		XMLTest( "Query attribute: int as double", 1, (int)dVal );
599 		XMLTest( "Query attribute: int as double", 1, (int)ele->DoubleAttribute("attr0"));
600 
601 		result = ele->QueryDoubleAttribute( "attr1", &dVal );
602 		XMLTest( "Query attribute: double as double", XML_SUCCESS, result);
603 		XMLTest( "Query attribute: double as double", 2.0, dVal );
604 		XMLTest( "Query attribute: double as double", 2.0, ele->DoubleAttribute("attr1") );
605 
606 		result = ele->QueryIntAttribute( "attr1", &iVal );
607 		XMLTest( "Query attribute: double as int", XML_SUCCESS, result);
608 		XMLTest( "Query attribute: double as int", 2, iVal );
609 
610 		result = ele->QueryIntAttribute( "attr2", &iVal );
611 		XMLTest( "Query attribute: not a number", XML_WRONG_ATTRIBUTE_TYPE, result );
612 		XMLTest( "Query attribute: not a number", 4.0, ele->DoubleAttribute("attr2", 4.0) );
613 
614 		result = ele->QueryIntAttribute( "bar", &iVal );
615 		XMLTest( "Query attribute: does not exist", XML_NO_ATTRIBUTE, result );
616 		XMLTest( "Query attribute: does not exist", true, ele->BoolAttribute("bar", true) );
617 	}
618 
619 	{
620 		const char* str = "<doc/>";
621 
622 		XMLDocument doc;
623 		doc.Parse( str );
624 		XMLTest( "Empty top element", false, doc.Error() );
625 
626 		XMLElement* ele = doc.FirstChildElement();
627 
628 		int iVal, iVal2;
629 		double dVal, dVal2;
630 
631 		ele->SetAttribute( "str", "strValue" );
632 		ele->SetAttribute( "int", 1 );
633 		ele->SetAttribute( "double", -1.0 );
634 
635 		const char* answer = 0;
636 		ele->QueryAttribute("str", &answer);
637 		XMLTest("Query char attribute", "strValue", answer);
638 
639 		const char* cStr = ele->Attribute( "str" );
640 		{
641 			XMLError queryResult = ele->QueryIntAttribute( "int", &iVal );
642 			XMLTest( "Query int attribute", XML_SUCCESS, queryResult);
643 		}
644 		{
645 			XMLError queryResult = ele->QueryDoubleAttribute( "double", &dVal );
646 			XMLTest( "Query double attribute", XML_SUCCESS, queryResult);
647 		}
648 
649 		{
650 			XMLError queryResult = ele->QueryAttribute( "int", &iVal2 );
651 			XMLTest( "Query int attribute generic", (int)XML_SUCCESS, queryResult);
652 		}
653 		{
654 			XMLError queryResult = ele->QueryAttribute( "double", &dVal2 );
655 			XMLTest( "Query double attribute generic", (int)XML_SUCCESS, queryResult);
656 		}
657 
658 		XMLTest( "Attribute match test", "strValue", ele->Attribute( "str", "strValue" ) );
659 		XMLTest( "Attribute round trip. c-string.", "strValue", cStr );
660 		XMLTest( "Attribute round trip. int.", 1, iVal );
661 		XMLTest( "Attribute round trip. double.", -1, (int)dVal );
662 		XMLTest( "Alternate query", true, iVal == iVal2 );
663 		XMLTest( "Alternate query", true, dVal == dVal2 );
664 		XMLTest( "Alternate query", true, iVal == ele->IntAttribute("int") );
665 		XMLTest( "Alternate query", true, dVal == ele->DoubleAttribute("double") );
666 	}
667 
668 	{
669 		XMLDocument doc;
670 		doc.LoadFile( "resources/utf8test.xml" );
671 		XMLTest( "Load utf8test.xml", false, doc.Error() );
672 
673 		// Get the attribute "value" from the "Russian" element and check it.
674 		XMLElement* element = doc.FirstChildElement( "document" )->FirstChildElement( "Russian" );
675 		const unsigned char correctValue[] = {	0xd1U, 0x86U, 0xd0U, 0xb5U, 0xd0U, 0xbdU, 0xd0U, 0xbdU,
676 												0xd0U, 0xbeU, 0xd1U, 0x81U, 0xd1U, 0x82U, 0xd1U, 0x8cU, 0 };
677 
678 		XMLTest( "UTF-8: Russian value.", (const char*)correctValue, element->Attribute( "value" ) );
679 
680 		const unsigned char russianElementName[] = {	0xd0U, 0xa0U, 0xd1U, 0x83U,
681 														0xd1U, 0x81U, 0xd1U, 0x81U,
682 														0xd0U, 0xbaU, 0xd0U, 0xb8U,
683 														0xd0U, 0xb9U, 0 };
684 		const char russianText[] = "<\xD0\xB8\xD0\xBC\xD0\xB5\xD0\xB5\xD1\x82>";
685 
686 		XMLText* text = doc.FirstChildElement( "document" )->FirstChildElement( (const char*) russianElementName )->FirstChild()->ToText();
687 		XMLTest( "UTF-8: Browsing russian element name.",
688 				 russianText,
689 				 text->Value() );
690 
691 		// Now try for a round trip.
692 		doc.SaveFile( "resources/out/utf8testout.xml" );
693 		XMLTest( "UTF-8: Save testout.xml", false, doc.Error() );
694 
695 		// Check the round trip.
696 		bool roundTripOkay = false;
697 
698 		FILE* saved  = fopen( "resources/out/utf8testout.xml", "r" );
699 		XMLTest( "UTF-8: Open utf8testout.xml", true, saved != 0 );
700 
701 		FILE* verify = fopen( "resources/utf8testverify.xml", "r" );
702 		XMLTest( "UTF-8: Open utf8testverify.xml", true, verify != 0 );
703 
704 		if ( saved && verify )
705 		{
706 			roundTripOkay = true;
707 			char verifyBuf[256];
708 			while ( fgets( verifyBuf, 256, verify ) )
709 			{
710 				char savedBuf[256];
711 				fgets( savedBuf, 256, saved );
712 				NullLineEndings( verifyBuf );
713 				NullLineEndings( savedBuf );
714 
715 				if ( strcmp( verifyBuf, savedBuf ) )
716 				{
717 					printf( "verify:%s<\n", verifyBuf );
718 					printf( "saved :%s<\n", savedBuf );
719 					roundTripOkay = false;
720 					break;
721 				}
722 			}
723 		}
724 		if ( saved )
725 			fclose( saved );
726 		if ( verify )
727 			fclose( verify );
728 		XMLTest( "UTF-8: Verified multi-language round trip.", true, roundTripOkay );
729 	}
730 
731 	// --------GetText()-----------
732 	{
733 		const char* str = "<foo>This is  text</foo>";
734 		XMLDocument doc;
735 		doc.Parse( str );
736 		XMLTest( "Double whitespace", false, doc.Error() );
737 		const XMLElement* element = doc.RootElement();
738 
739 		XMLTest( "GetText() normal use.", "This is  text", element->GetText() );
740 
741 		str = "<foo><b>This is text</b></foo>";
742 		doc.Parse( str );
743 		XMLTest( "Bold text simulation", false, doc.Error() );
744 		element = doc.RootElement();
745 
746 		XMLTest( "GetText() contained element.", element->GetText() == 0, true );
747 	}
748 
749 
750 	// --------SetText()-----------
751 	{
752 		const char* str = "<foo></foo>";
753 		XMLDocument doc;
754 		doc.Parse( str );
755 		XMLTest( "Empty closed element", false, doc.Error() );
756 		XMLElement* element = doc.RootElement();
757 
758 		element->SetText("darkness.");
759 		XMLTest( "SetText() normal use (open/close).", "darkness.", element->GetText() );
760 
761 		element->SetText("blue flame.");
762 		XMLTest( "SetText() replace.", "blue flame.", element->GetText() );
763 
764 		str = "<foo/>";
765 		doc.Parse( str );
766 		XMLTest( "Empty self-closed element", false, doc.Error() );
767 		element = doc.RootElement();
768 
769 		element->SetText("The driver");
770 		XMLTest( "SetText() normal use. (self-closing)", "The driver", element->GetText() );
771 
772 		element->SetText("<b>horses</b>");
773 		XMLTest( "SetText() replace with tag-like text.", "<b>horses</b>", element->GetText() );
774 		//doc.Print();
775 
776 		str = "<foo><bar>Text in nested element</bar></foo>";
777 		doc.Parse( str );
778 		XMLTest( "Text in nested element", false, doc.Error() );
779 		element = doc.RootElement();
780 
781 		element->SetText("wolves");
782 		XMLTest( "SetText() prefix to nested non-text children.", "wolves", element->GetText() );
783 
784 		str = "<foo/>";
785 		doc.Parse( str );
786 		XMLTest( "Empty self-closed element round 2", false, doc.Error() );
787 		element = doc.RootElement();
788 
789 		element->SetText( "str" );
790 		XMLTest( "SetText types", "str", element->GetText() );
791 
792 		element->SetText( 1 );
793 		XMLTest( "SetText types", "1", element->GetText() );
794 
795 		element->SetText( 1U );
796 		XMLTest( "SetText types", "1", element->GetText() );
797 
798 		element->SetText( true );
799 		XMLTest( "SetText types", "true", element->GetText() );
800 
801 		element->SetText( 1.5f );
802 		XMLTest( "SetText types", "1.5", element->GetText() );
803 
804 		element->SetText( 1.5 );
805 		XMLTest( "SetText types", "1.5", element->GetText() );
806 	}
807 
808 	// ---------- Attributes ---------
809 	{
810 		static const int64_t BIG = -123456789012345678;
811         static const uint64_t BIG_POS = 123456789012345678;
812 		XMLDocument doc;
813 		XMLElement* element = doc.NewElement("element");
814 		doc.InsertFirstChild(element);
815 
816 		{
817 			element->SetAttribute("attrib", int(-100));
818 			{
819 				int v = 0;
820 				XMLError queryResult = element->QueryIntAttribute("attrib", &v);
821 				XMLTest("Attribute: int", XML_SUCCESS, queryResult, true);
822 				XMLTest("Attribute: int", -100, v, true);
823 			}
824 			{
825 				int v = 0;
826 				XMLError queryResult = element->QueryAttribute("attrib", &v);
827 				XMLTest("Attribute: int", (int)XML_SUCCESS, queryResult, true);
828 				XMLTest("Attribute: int", -100, v, true);
829 			}
830 			XMLTest("Attribute: int", -100, element->IntAttribute("attrib"), true);
831 		}
832 		{
833 			element->SetAttribute("attrib", unsigned(100));
834 			{
835 				unsigned v = 0;
836 				XMLError queryResult = element->QueryUnsignedAttribute("attrib", &v);
837 				XMLTest("Attribute: unsigned", XML_SUCCESS, queryResult, true);
838 				XMLTest("Attribute: unsigned", unsigned(100), v, true);
839 			}
840 			{
841 				unsigned v = 0;
842 				XMLError queryResult = element->QueryAttribute("attrib", &v);
843 				XMLTest("Attribute: unsigned", (int)XML_SUCCESS, queryResult, true);
844 				XMLTest("Attribute: unsigned", unsigned(100), v, true);
845 			}
846 			{
847 				const char* v = "failed";
848 				XMLError queryResult = element->QueryStringAttribute("not-attrib", &v);
849 				XMLTest("Attribute: string default", false, queryResult == XML_SUCCESS);
850 				queryResult = element->QueryStringAttribute("attrib", &v);
851 				XMLTest("Attribute: string", XML_SUCCESS, queryResult, true);
852 				XMLTest("Attribute: string", "100", v);
853 			}
854 			XMLTest("Attribute: unsigned", unsigned(100), element->UnsignedAttribute("attrib"), true);
855 		}
856 		{
857 			element->SetAttribute("attrib", BIG);
858 			{
859 				int64_t v = 0;
860 				XMLError queryResult = element->QueryInt64Attribute("attrib", &v);
861 				XMLTest("Attribute: int64_t", XML_SUCCESS, queryResult, true);
862 				XMLTest("Attribute: int64_t", BIG, v, true);
863 			}
864 			{
865 				int64_t v = 0;
866 				XMLError queryResult = element->QueryAttribute("attrib", &v);
867 				XMLTest("Attribute: int64_t", (int)XML_SUCCESS, queryResult, true);
868 				XMLTest("Attribute: int64_t", BIG, v, true);
869 			}
870 			XMLTest("Attribute: int64_t", BIG, element->Int64Attribute("attrib"), true);
871 		}
872         {
873             element->SetAttribute("attrib", BIG_POS);
874             {
875                 uint64_t v = 0;
876                 XMLError queryResult = element->QueryUnsigned64Attribute("attrib", &v);
877                 XMLTest("Attribute: uint64_t", XML_SUCCESS, queryResult, true);
878                 XMLTest("Attribute: uint64_t", BIG_POS, v, true);
879             }
880             {
881                 uint64_t v = 0;
882 				XMLError queryResult = element->QueryAttribute("attrib", &v);
883                 XMLTest("Attribute: uint64_t", (int)XML_SUCCESS, queryResult, true);
884                 XMLTest("Attribute: uint64_t", BIG_POS, v, true);
885             }
886             XMLTest("Attribute: uint64_t", BIG_POS, element->Unsigned64Attribute("attrib"), true);
887         }
888         {
889 			element->SetAttribute("attrib", true);
890 			{
891 				bool v = false;
892 				XMLError queryResult = element->QueryBoolAttribute("attrib", &v);
893 				XMLTest("Attribute: bool", XML_SUCCESS, queryResult, true);
894 				XMLTest("Attribute: bool", true, v, true);
895 			}
896 			{
897 				bool v = false;
898 				XMLError queryResult = element->QueryAttribute("attrib", &v);
899 				XMLTest("Attribute: bool", (int)XML_SUCCESS, queryResult, true);
900 				XMLTest("Attribute: bool", true, v, true);
901 			}
902 			XMLTest("Attribute: bool", true, element->BoolAttribute("attrib"), true);
903 		}
904 		{
905 			element->SetAttribute("attrib", true);
906 			const char* result = element->Attribute("attrib");
907 			XMLTest("Bool true is 'true'", "true", result);
908 
909 			XMLUtil::SetBoolSerialization("1", "0");
910 			element->SetAttribute("attrib", true);
911 			result = element->Attribute("attrib");
912 			XMLTest("Bool true is '1'", "1", result);
913 
914 			XMLUtil::SetBoolSerialization(0, 0);
915 		}
916 		{
917 			element->SetAttribute("attrib", 100.0);
918 			{
919 				double v = 0;
920 				XMLError queryResult = element->QueryDoubleAttribute("attrib", &v);
921 				XMLTest("Attribute: double", XML_SUCCESS, queryResult, true);
922 				XMLTest("Attribute: double", 100.0, v, true);
923 			}
924 			{
925 				double v = 0;
926 				XMLError queryResult = element->QueryAttribute("attrib", &v);
927 				XMLTest("Attribute: bool", (int)XML_SUCCESS, queryResult, true);
928 				XMLTest("Attribute: double", 100.0, v, true);
929 			}
930 			XMLTest("Attribute: double", 100.0, element->DoubleAttribute("attrib"), true);
931 		}
932 		{
933 			element->SetAttribute("attrib", 100.0f);
934 			{
935 				float v = 0;
936 				XMLError queryResult = element->QueryFloatAttribute("attrib", &v);
937 				XMLTest("Attribute: float", XML_SUCCESS, queryResult, true);
938 				XMLTest("Attribute: float", 100.0f, v, true);
939 			}
940 			{
941 				float v = 0;
942 				XMLError queryResult = element->QueryAttribute("attrib", &v);
943 				XMLTest("Attribute: float", (int)XML_SUCCESS, queryResult, true);
944 				XMLTest("Attribute: float", 100.0f, v, true);
945 			}
946 			XMLTest("Attribute: float", 100.0f, element->FloatAttribute("attrib"), true);
947 		}
948 		{
949 			element->SetText(BIG);
950 			int64_t v = 0;
951 			XMLError queryResult = element->QueryInt64Text(&v);
952 			XMLTest("Element: int64_t", XML_SUCCESS, queryResult, true);
953 			XMLTest("Element: int64_t", BIG, v, true);
954 		}
955         {
956             element->SetText(BIG_POS);
957             uint64_t v = 0;
958             XMLError queryResult = element->QueryUnsigned64Text(&v);
959             XMLTest("Element: uint64_t", XML_SUCCESS, queryResult, true);
960             XMLTest("Element: uint64_t", BIG_POS, v, true);
961         }
962     }
963 
964 	// ---------- XMLPrinter stream mode ------
965 	{
966 		{
967 			FILE* printerfp = fopen("resources/out/printer.xml", "w");
968 			XMLTest("Open printer.xml", true, printerfp != 0);
969 			XMLPrinter printer(printerfp);
970 			printer.OpenElement("foo");
971 			printer.PushAttribute("attrib-text", "text");
972 			printer.PushAttribute("attrib-int", int(1));
973 			printer.PushAttribute("attrib-unsigned", unsigned(2));
974 			printer.PushAttribute("attrib-int64", int64_t(3));
975 			printer.PushAttribute("attrib-uint64", uint64_t(37));
976 			printer.PushAttribute("attrib-bool", true);
977 			printer.PushAttribute("attrib-double", 4.0);
978 			printer.CloseElement();
979 			fclose(printerfp);
980 		}
981 		{
982 			XMLDocument doc;
983 			doc.LoadFile("resources/out/printer.xml");
984 			XMLTest("XMLPrinter Stream mode: load", XML_SUCCESS, doc.ErrorID(), true);
985 
986 			const XMLDocument& cdoc = doc;
987 
988 			const XMLAttribute* attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-text");
989 			XMLTest("attrib-text", "text", attrib->Value(), true);
990 			attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int");
991 			XMLTest("attrib-int", int(1), attrib->IntValue(), true);
992 			attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-unsigned");
993 			XMLTest("attrib-unsigned", unsigned(2), attrib->UnsignedValue(), true);
994 			attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int64");
995 			XMLTest("attrib-int64", int64_t(3), attrib->Int64Value(), true);
996 			attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-uint64");
997 			XMLTest("attrib-uint64", uint64_t(37), attrib->Unsigned64Value(), true);
998 			attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-bool");
999 			XMLTest("attrib-bool", true, attrib->BoolValue(), true);
1000 			attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-double");
1001 			XMLTest("attrib-double", 4.0, attrib->DoubleValue(), true);
1002 		}
1003 		// Add API_testcatse :PushDeclaration();PushText();PushComment()
1004 		{
1005 			FILE* fp1 = fopen("resources/out/printer_1.xml", "w");
1006 			XMLPrinter printer(fp1);
1007 
1008 			printer.PushDeclaration("version = '1.0' enconding = 'utf-8'");
1009 
1010 			printer.OpenElement("foo");
1011 			printer.PushAttribute("attrib-text", "text");
1012 
1013 			printer.OpenElement("text");
1014 			printer.PushText("Tinyxml2");
1015 			printer.CloseElement();
1016 
1017 			printer.OpenElement("int");
1018 			printer.PushText(int(11));
1019 			printer.CloseElement();
1020 
1021 			printer.OpenElement("unsigned");
1022 			printer.PushText(unsigned(12));
1023 			printer.CloseElement();
1024 
1025 			printer.OpenElement("int64_t");
1026 			printer.PushText(int64_t(13));
1027 			printer.CloseElement();
1028 
1029 			printer.OpenElement("uint64_t");
1030 			printer.PushText(uint64_t(14));
1031 			printer.CloseElement();
1032 
1033 			printer.OpenElement("bool");
1034 			printer.PushText(true);
1035 			printer.CloseElement();
1036 
1037 			printer.OpenElement("float");
1038 			printer.PushText("1.56");
1039 			printer.CloseElement();
1040 
1041 			printer.OpenElement("double");
1042 			printer.PushText("12.12");
1043 			printer.CloseElement();
1044 
1045 			printer.OpenElement("comment");
1046 			printer.PushComment("this is Tinyxml2");
1047 			printer.CloseElement();
1048 
1049 			printer.CloseElement();
1050 			fclose(fp1);
1051 		}
1052 		{
1053 			XMLDocument doc;
1054 			doc.LoadFile("resources/out/printer_1.xml");
1055 			XMLTest("XMLPrinter Stream mode: load", XML_SUCCESS, doc.ErrorID(), true);
1056 
1057 			const XMLDocument& cdoc = doc;
1058 
1059 			const  XMLElement* root = cdoc.FirstChildElement("foo");
1060 
1061 			const char* text_value;
1062 			text_value = root->FirstChildElement("text")->GetText();
1063 			XMLTest("PushText( const char* text, bool cdata=false ) test", "Tinyxml2", text_value);
1064 
1065 			int  int_value;
1066 			int_value = root->FirstChildElement("int")->IntText();
1067 			XMLTest("PushText( int value ) test", 11, int_value);
1068 
1069 			unsigned  unsigned_value;
1070 			unsigned_value = root->FirstChildElement("unsigned")->UnsignedText();
1071 			XMLTest("PushText( unsigned value ) test", (unsigned)12, unsigned_value);
1072 
1073 			int64_t  int64_t_value;
1074 			int64_t_value = root->FirstChildElement("int64_t")->Int64Text();
1075 			XMLTest("PushText( int64_t value ) test", (int64_t) 13, int64_t_value);
1076 
1077 			uint64_t uint64_t_value;
1078 			uint64_t_value = root->FirstChildElement("uint64_t")->Unsigned64Text();
1079 			XMLTest("PushText( uint64_t value ) test", (uint64_t) 14, uint64_t_value);
1080 
1081 			float  float_value;
1082 			float_value = root->FirstChildElement("float")->FloatText();
1083 			XMLTest("PushText( float value ) test", 1.56f, float_value);
1084 
1085 			double double_value;
1086 			double_value = root->FirstChildElement("double")->DoubleText();
1087 			XMLTest("PushText( double value ) test", 12.12, double_value);
1088 
1089 			bool bool_value;
1090 			bool_value = root->FirstChildElement("bool")->BoolText();
1091 			XMLTest("PushText( bool value ) test", true, bool_value);
1092 
1093 			const XMLComment* comment = root->FirstChildElement("comment")->FirstChild()->ToComment();
1094 			const char* comment_value = comment->Value();
1095 			XMLTest("PushComment() test", "this is Tinyxml2", comment_value);
1096 
1097 			const XMLDeclaration* declaration = cdoc.FirstChild()->ToDeclaration();
1098 			const char* declaration_value = declaration->Value();
1099 			XMLTest("PushDeclaration() test", "version = '1.0' enconding = 'utf-8'", declaration_value);
1100 		}
1101 	}
1102 
1103 
1104 	// ---------- CDATA ---------------
1105 	{
1106 		const char* str =	"<xmlElement>"
1107 								"<![CDATA["
1108 									"I am > the rules!\n"
1109 									"...since I make symbolic puns"
1110 								"]]>"
1111 							"</xmlElement>";
1112 		XMLDocument doc;
1113 		doc.Parse( str );
1114 		XMLTest( "CDATA symbolic puns round 1", false, doc.Error() );
1115 		doc.Print();
1116 
1117 		XMLTest( "CDATA parse.", "I am > the rules!\n...since I make symbolic puns",
1118 								 doc.FirstChildElement()->FirstChild()->Value(),
1119 								 false );
1120 	}
1121 
1122 	// ----------- CDATA -------------
1123 	{
1124 		const char* str =	"<xmlElement>"
1125 								"<![CDATA["
1126 									"<b>I am > the rules!</b>\n"
1127 									"...since I make symbolic puns"
1128 								"]]>"
1129 							"</xmlElement>";
1130 		XMLDocument doc;
1131 		doc.Parse( str );
1132 		XMLTest( "CDATA symbolic puns round 2", false, doc.Error() );
1133 		doc.Print();
1134 
1135 		XMLTest( "CDATA parse. [ tixml1:1480107 ]",
1136 								 "<b>I am > the rules!</b>\n...since I make symbolic puns",
1137 								 doc.FirstChildElement()->FirstChild()->Value(),
1138 								 false );
1139 	}
1140 
1141 	// InsertAfterChild causes crash.
1142 	{
1143 		// InsertBeforeChild and InsertAfterChild causes crash.
1144 		XMLDocument doc;
1145 		XMLElement* parent = doc.NewElement( "Parent" );
1146 		doc.InsertFirstChild( parent );
1147 
1148 		XMLElement* childText0 = doc.NewElement( "childText0" );
1149 		XMLElement* childText1 = doc.NewElement( "childText1" );
1150 
1151 		XMLNode* childNode0 = parent->InsertEndChild( childText0 );
1152 		XMLTest( "InsertEndChild() return", true, childNode0 == childText0 );
1153 		XMLNode* childNode1 = parent->InsertAfterChild( childNode0, childText1 );
1154 		XMLTest( "InsertAfterChild() return", true, childNode1 == childText1 );
1155 
1156 		XMLTest( "Test InsertAfterChild on empty node. ", true, ( childNode1 == parent->LastChild() ) );
1157 	}
1158 
1159 	{
1160 		// Entities not being written correctly.
1161 		// From Lynn Allen
1162 
1163 		const char* passages =
1164 			"<?xml version=\"1.0\" standalone=\"no\" ?>"
1165 			"<passages count=\"006\" formatversion=\"20020620\">"
1166 				"<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
1167 				" It also has &lt;, &gt;, and &amp;, as well as a fake copyright &#xA9;.\"> </psg>"
1168 			"</passages>";
1169 
1170 		XMLDocument doc;
1171 		doc.Parse( passages );
1172 		XMLTest( "Entity transformation parse round 1", false, doc.Error() );
1173 		XMLElement* psg = doc.RootElement()->FirstChildElement();
1174 		const char* context = psg->Attribute( "context" );
1175 		const char* expected = "Line 5 has \"quotation marks\" and 'apostrophe marks'. It also has <, >, and &, as well as a fake copyright \xC2\xA9.";
1176 
1177 		XMLTest( "Entity transformation: read. ", expected, context, true );
1178 
1179 		const char* textFilePath = "resources/out/textfile.txt";
1180 		FILE* textfile = fopen( textFilePath, "w" );
1181 		XMLTest( "Entity transformation: open text file for writing", true, textfile != 0, true );
1182 		if ( textfile )
1183 		{
1184 			XMLPrinter streamer( textfile );
1185 			bool acceptResult = psg->Accept( &streamer );
1186 			fclose( textfile );
1187 			XMLTest( "Entity transformation: Accept", true, acceptResult );
1188 		}
1189 
1190 		textfile = fopen( textFilePath, "r" );
1191 		XMLTest( "Entity transformation: open text file for reading", true, textfile != 0, true );
1192 		if ( textfile )
1193 		{
1194 			char buf[ 1024 ];
1195 			fgets( buf, 1024, textfile );
1196 			XMLTest( "Entity transformation: write. ",
1197 					 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
1198 					 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright \xC2\xA9.\"/>\n",
1199 					 buf, false );
1200 			fclose( textfile );
1201 		}
1202 	}
1203 
1204 	{
1205 		// Suppress entities.
1206 		const char* passages =
1207 			"<?xml version=\"1.0\" standalone=\"no\" ?>"
1208 			"<passages count=\"006\" formatversion=\"20020620\">"
1209 				"<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.\">Crazy &ttk;</psg>"
1210 			"</passages>";
1211 
1212 		XMLDocument doc( false );
1213 		doc.Parse( passages );
1214 		XMLTest( "Entity transformation parse round 2", false, doc.Error() );
1215 
1216 		XMLTest( "No entity parsing.",
1217 				 "Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.",
1218 				 doc.FirstChildElement()->FirstChildElement()->Attribute( "context" ) );
1219 		XMLTest( "No entity parsing.", "Crazy &ttk;",
1220 				 doc.FirstChildElement()->FirstChildElement()->FirstChild()->Value() );
1221 		doc.Print();
1222 	}
1223 
1224 	{
1225 		const char* test = "<?xml version='1.0'?><a.elem xmi.version='2.0'/>";
1226 
1227 		XMLDocument doc;
1228 		doc.Parse( test );
1229 		XMLTest( "dot in names", false, doc.Error() );
1230 		XMLTest( "dot in names", "a.elem", doc.FirstChildElement()->Name() );
1231 		XMLTest( "dot in names", "2.0", doc.FirstChildElement()->Attribute( "xmi.version" ) );
1232 	}
1233 
1234 	{
1235 		const char* test = "<element><Name>1.1 Start easy ignore fin thickness&#xA;</Name></element>";
1236 
1237 		XMLDocument doc;
1238 		doc.Parse( test );
1239 		XMLTest( "fin thickness", false, doc.Error() );
1240 
1241 		XMLText* text = doc.FirstChildElement()->FirstChildElement()->FirstChild()->ToText();
1242 		XMLTest( "Entity with one digit.",
1243 				 "1.1 Start easy ignore fin thickness\n", text->Value(),
1244 				 false );
1245 	}
1246 
1247 	{
1248 		// DOCTYPE not preserved (950171)
1249 		//
1250 		const char* doctype =
1251 			"<?xml version=\"1.0\" ?>"
1252 			"<!DOCTYPE PLAY SYSTEM 'play.dtd'>"
1253 			"<!ELEMENT title (#PCDATA)>"
1254 			"<!ELEMENT books (title,authors)>"
1255 			"<element />";
1256 
1257 		XMLDocument doc;
1258 		doc.Parse( doctype );
1259 		XMLTest( "PLAY SYSTEM parse", false, doc.Error() );
1260 		doc.SaveFile( "resources/out/test7.xml" );
1261 		XMLTest( "PLAY SYSTEM save", false, doc.Error() );
1262 		doc.DeleteChild( doc.RootElement() );
1263 		doc.LoadFile( "resources/out/test7.xml" );
1264 		XMLTest( "PLAY SYSTEM load", false, doc.Error() );
1265 		doc.Print();
1266 
1267 		const XMLUnknown* decl = doc.FirstChild()->NextSibling()->ToUnknown();
1268 		XMLTest( "Correct value of unknown.", "DOCTYPE PLAY SYSTEM 'play.dtd'", decl->Value() );
1269 
1270 	}
1271 
1272 	{
1273 		// Comments do not stream out correctly.
1274 		const char* doctype =
1275 			"<!-- Somewhat<evil> -->";
1276 		XMLDocument doc;
1277 		doc.Parse( doctype );
1278 		XMLTest( "Comment somewhat evil", false, doc.Error() );
1279 
1280 		XMLComment* comment = doc.FirstChild()->ToComment();
1281 
1282 		XMLTest( "Comment formatting.", " Somewhat<evil> ", comment->Value() );
1283 	}
1284 	{
1285 		// Double attributes
1286 		const char* doctype = "<element attr='red' attr='blue' />";
1287 
1288 		XMLDocument doc;
1289 		doc.Parse( doctype );
1290 
1291 		XMLTest( "Parsing repeated attributes.", XML_ERROR_PARSING_ATTRIBUTE, doc.ErrorID() );	// is an  error to tinyxml (didn't use to be, but caused issues)
1292 		doc.PrintError();
1293 	}
1294 
1295 	{
1296 		// Embedded null in stream.
1297 		const char* doctype = "<element att\0r='red' attr='blue' />";
1298 
1299 		XMLDocument doc;
1300 		doc.Parse( doctype );
1301 		XMLTest( "Embedded null throws error.", true, doc.Error() );
1302 	}
1303 
1304 	{
1305 		// Empty documents should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
1306 		const char* str = "";
1307 		XMLDocument doc;
1308 		doc.Parse( str );
1309 		XMLTest( "Empty document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
1310 
1311 		// But be sure there is an error string!
1312 		const char* errorStr = doc.ErrorStr();
1313 		XMLTest("Error string should be set",
1314 			"Error=XML_ERROR_EMPTY_DOCUMENT ErrorID=13 (0xd) Line number=0",
1315 			errorStr);
1316 	}
1317 
1318 	{
1319 		// Documents with all whitespaces should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
1320 		const char* str = "    ";
1321 		XMLDocument doc;
1322 		doc.Parse( str );
1323 		XMLTest( "All whitespaces document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
1324 	}
1325 
1326 	{
1327 		// Low entities
1328 		XMLDocument doc;
1329 		doc.Parse( "<test>&#x0e;</test>" );
1330 		XMLTest( "Hex values", false, doc.Error() );
1331 		const char result[] = { 0x0e, 0 };
1332 		XMLTest( "Low entities.", result, doc.FirstChildElement()->GetText() );
1333 		doc.Print();
1334 	}
1335 
1336 	{
1337 		// Attribute values with trailing quotes not handled correctly
1338 		XMLDocument doc;
1339 		doc.Parse( "<foo attribute=bar\" />" );
1340 		XMLTest( "Throw error with bad end quotes.", true, doc.Error() );
1341 	}
1342 
1343 	{
1344 		// [ 1663758 ] Failure to report error on bad XML
1345 		XMLDocument xml;
1346 		xml.Parse("<x>");
1347 		XMLTest("Missing end tag at end of input", true, xml.Error());
1348 		xml.Parse("<x> ");
1349 		XMLTest("Missing end tag with trailing whitespace", true, xml.Error());
1350 		xml.Parse("<x></y>");
1351 		XMLTest("Mismatched tags", XML_ERROR_MISMATCHED_ELEMENT, xml.ErrorID() );
1352 	}
1353 
1354 
1355 	{
1356 		// [ 1475201 ] TinyXML parses entities in comments
1357 		XMLDocument xml;
1358 		xml.Parse("<!-- declarations for <head> & <body> -->"
1359 				  "<!-- far &amp; away -->" );
1360 		XMLTest( "Declarations for head and body", false, xml.Error() );
1361 
1362 		XMLNode* e0 = xml.FirstChild();
1363 		XMLNode* e1 = e0->NextSibling();
1364 		XMLComment* c0 = e0->ToComment();
1365 		XMLComment* c1 = e1->ToComment();
1366 
1367 		XMLTest( "Comments ignore entities.", " declarations for <head> & <body> ", c0->Value(), true );
1368 		XMLTest( "Comments ignore entities.", " far &amp; away ", c1->Value(), true );
1369 	}
1370 
1371 	{
1372 		XMLDocument xml;
1373 		xml.Parse( "<Parent>"
1374 						"<child1 att=''/>"
1375 						"<!-- With this comment, child2 will not be parsed! -->"
1376 						"<child2 att=''/>"
1377 					"</Parent>" );
1378 		XMLTest( "Comments iteration", false, xml.Error() );
1379 		xml.Print();
1380 
1381 		int count = 0;
1382 
1383 		for( XMLNode* ele = xml.FirstChildElement( "Parent" )->FirstChild();
1384 			 ele;
1385 			 ele = ele->NextSibling() )
1386 		{
1387 			++count;
1388 		}
1389 
1390 		XMLTest( "Comments iterate correctly.", 3, count );
1391 	}
1392 
1393 	{
1394 		// trying to repro [1874301]. If it doesn't go into an infinite loop, all is well.
1395 		unsigned char buf[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?><feed><![CDATA[Test XMLblablablalblbl";
1396 		buf[60] = 239;
1397 		buf[61] = 0;
1398 
1399 		XMLDocument doc;
1400 		doc.Parse( (const char*)buf);
1401 		XMLTest( "Broken CDATA", true, doc.Error() );
1402 	}
1403 
1404 
1405 	{
1406 		// bug 1827248 Error while parsing a little bit malformed file
1407 		// Actually not malformed - should work.
1408 		XMLDocument xml;
1409 		xml.Parse( "<attributelist> </attributelist >" );
1410 		XMLTest( "Handle end tag whitespace", false, xml.Error() );
1411 	}
1412 
1413 	{
1414 		// This one must not result in an infinite loop
1415 		XMLDocument xml;
1416 		xml.Parse( "<infinite>loop" );
1417 		XMLTest( "No closing element", true, xml.Error() );
1418 		XMLTest( "Infinite loop test.", true, true );
1419 	}
1420 #endif
1421 	{
1422 		const char* pub = "<?xml version='1.0'?> <element><sub/></element> <!--comment--> <!DOCTYPE>";
1423 		XMLDocument doc;
1424 		doc.Parse( pub );
1425 		XMLTest( "Trailing DOCTYPE", false, doc.Error() );
1426 
1427 		XMLDocument clone;
1428 		for( const XMLNode* node=doc.FirstChild(); node; node=node->NextSibling() ) {
1429 			XMLNode* copy = node->ShallowClone( &clone );
1430 			clone.InsertEndChild( copy );
1431 		}
1432 
1433 		clone.Print();
1434 
1435 		int count=0;
1436 		const XMLNode* a=clone.FirstChild();
1437 		const XMLNode* b=doc.FirstChild();
1438 		for( ; a && b; a=a->NextSibling(), b=b->NextSibling() ) {
1439 			++count;
1440 			XMLTest( "Clone and Equal", true, a->ShallowEqual( b ));
1441 		}
1442 		XMLTest( "Clone and Equal", 4, count );
1443 	}
1444 
1445 	{
1446 		// Deep Cloning of root element.
1447 		XMLDocument doc2;
1448 		XMLPrinter printer1;
1449 		{
1450 			// Make sure doc1 is deleted before we test doc2
1451 			const char* xml =
1452 				"<root>"
1453 				"    <child1 foo='bar'/>"
1454 				"    <!-- comment thing -->"
1455 				"    <child2 val='1'>Text</child2>"
1456 				"</root>";
1457 			XMLDocument doc;
1458 			doc.Parse(xml);
1459 			XMLTest( "Parse before deep cloning root element", false, doc.Error() );
1460 
1461 			doc.Print(&printer1);
1462 			XMLNode* root = doc.RootElement()->DeepClone(&doc2);
1463 			doc2.InsertFirstChild(root);
1464 		}
1465 		XMLPrinter printer2;
1466 		doc2.Print(&printer2);
1467 
1468 		XMLTest("Deep clone of element.", printer1.CStr(), printer2.CStr(), true);
1469 	}
1470 
1471 	{
1472 		// Deep Cloning of sub element.
1473 		XMLDocument doc2;
1474 		XMLPrinter printer1;
1475 		{
1476 			// Make sure doc1 is deleted before we test doc2
1477 			const char* xml =
1478 				"<?xml version ='1.0'?>"
1479 				"<root>"
1480 				"    <child1 foo='bar'/>"
1481 				"    <!-- comment thing -->"
1482 				"    <child2 val='1'>Text</child2>"
1483 				"</root>";
1484 			XMLDocument doc;
1485 			doc.Parse(xml);
1486 			XMLTest( "Parse before deep cloning sub element", false, doc.Error() );
1487 
1488 			const XMLElement* subElement = doc.FirstChildElement("root")->FirstChildElement("child2");
1489 			bool acceptResult = subElement->Accept(&printer1);
1490 			XMLTest( "Accept before deep cloning", true, acceptResult );
1491 
1492 			XMLNode* clonedSubElement = subElement->DeepClone(&doc2);
1493 			doc2.InsertFirstChild(clonedSubElement);
1494 		}
1495 		XMLPrinter printer2;
1496 		doc2.Print(&printer2);
1497 
1498 		XMLTest("Deep clone of sub-element.", printer1.CStr(), printer2.CStr(), true);
1499 	}
1500 
1501 	{
1502 		// Deep cloning of document.
1503 		XMLDocument doc2;
1504 		XMLPrinter printer1;
1505 		{
1506 			// Make sure doc1 is deleted before we test doc2
1507 			const char* xml =
1508 				"<?xml version ='1.0'?>"
1509 				"<!-- Top level comment. -->"
1510 				"<root>"
1511 				"    <child1 foo='bar'/>"
1512 				"    <!-- comment thing -->"
1513 				"    <child2 val='1'>Text</child2>"
1514 				"</root>";
1515 			XMLDocument doc;
1516 			doc.Parse(xml);
1517 			XMLTest( "Parse before deep cloning document", false, doc.Error() );
1518 			doc.Print(&printer1);
1519 
1520 			doc.DeepCopy(&doc2);
1521 		}
1522 		XMLPrinter printer2;
1523 		doc2.Print(&printer2);
1524 
1525 		XMLTest("DeepCopy of document.", printer1.CStr(), printer2.CStr(), true);
1526 	}
1527 
1528 
1529  	{
1530 		// This shouldn't crash.
1531 		XMLDocument doc;
1532 		if(XML_SUCCESS != doc.LoadFile( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ))
1533 		{
1534 			doc.PrintError();
1535 		}
1536 		XMLTest( "Error in snprinf handling.", true, doc.Error() );
1537 	}
1538 
1539 	{
1540 		// Attribute ordering.
1541 		static const char* xml = "<element attrib1=\"1\" attrib2=\"2\" attrib3=\"3\" />";
1542 		XMLDocument doc;
1543 		doc.Parse( xml );
1544 		XMLTest( "Parse for attribute ordering", false, doc.Error() );
1545 		XMLElement* ele = doc.FirstChildElement();
1546 
1547 		const XMLAttribute* a = ele->FirstAttribute();
1548 		XMLTest( "Attribute order", "1", a->Value() );
1549 		a = a->Next();
1550 		XMLTest( "Attribute order", "2", a->Value() );
1551 		a = a->Next();
1552 		XMLTest( "Attribute order", "3", a->Value() );
1553 		XMLTest( "Attribute order", "attrib3", a->Name() );
1554 
1555 		ele->DeleteAttribute( "attrib2" );
1556 		a = ele->FirstAttribute();
1557 		XMLTest( "Attribute order", "1", a->Value() );
1558 		a = a->Next();
1559 		XMLTest( "Attribute order", "3", a->Value() );
1560 
1561 		ele->DeleteAttribute( "attrib1" );
1562 		ele->DeleteAttribute( "attrib3" );
1563 		XMLTest( "Attribute order (empty)", true, ele->FirstAttribute() == 0 );
1564 	}
1565 
1566 	{
1567 		// Make sure an attribute with a space in it succeeds.
1568 		static const char* xml0 = "<element attribute1= \"Test Attribute\"/>";
1569 		static const char* xml1 = "<element attribute1 =\"Test Attribute\"/>";
1570 		static const char* xml2 = "<element attribute1 = \"Test Attribute\"/>";
1571 		XMLDocument doc0;
1572 		doc0.Parse( xml0 );
1573 		XMLTest( "Parse attribute with space 1", false, doc0.Error() );
1574 		XMLDocument doc1;
1575 		doc1.Parse( xml1 );
1576 		XMLTest( "Parse attribute with space 2", false, doc1.Error() );
1577 		XMLDocument doc2;
1578 		doc2.Parse( xml2 );
1579 		XMLTest( "Parse attribute with space 3", false, doc2.Error() );
1580 
1581 		XMLElement* ele = 0;
1582 		ele = doc0.FirstChildElement();
1583 		XMLTest( "Attribute with space #1", "Test Attribute", ele->Attribute( "attribute1" ) );
1584 		ele = doc1.FirstChildElement();
1585 		XMLTest( "Attribute with space #2", "Test Attribute", ele->Attribute( "attribute1" ) );
1586 		ele = doc2.FirstChildElement();
1587 		XMLTest( "Attribute with space #3", "Test Attribute", ele->Attribute( "attribute1" ) );
1588 	}
1589 
1590 	{
1591 		// Make sure we don't go into an infinite loop.
1592 		static const char* xml = "<doc><element attribute='attribute'/><element attribute='attribute'/></doc>";
1593 		XMLDocument doc;
1594 		doc.Parse( xml );
1595 		XMLTest( "Parse two elements with attribute", false, doc.Error() );
1596 		XMLElement* ele0 = doc.FirstChildElement()->FirstChildElement();
1597 		XMLElement* ele1 = ele0->NextSiblingElement();
1598 		bool equal = ele0->ShallowEqual( ele1 );
1599 
1600 		XMLTest( "Infinite loop in shallow equal.", true, equal );
1601 	}
1602 
1603 	// -------- Handles ------------
1604 	{
1605 		static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1606 		XMLDocument doc;
1607 		doc.Parse( xml );
1608 		XMLTest( "Handle, parse element with attribute and nested element", false, doc.Error() );
1609 
1610 		{
1611 			XMLElement* ele = XMLHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
1612 			XMLTest( "Handle, non-const, element is found", true, ele != 0 );
1613 			XMLTest( "Handle, non-const, element name matches", "sub", ele->Value() );
1614 		}
1615 
1616 		{
1617 			XMLHandle docH( doc );
1618 			XMLElement* ele = docH.FirstChildElement( "noSuchElement" ).FirstChildElement( "element" ).ToElement();
1619 			XMLTest( "Handle, non-const, element not found", true, ele == 0 );
1620 		}
1621 
1622 		{
1623 			const XMLElement* ele = XMLConstHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
1624 			XMLTest( "Handle, const, element is found", true, ele != 0 );
1625 			XMLTest( "Handle, const, element name matches", "sub", ele->Value() );
1626 		}
1627 
1628 		{
1629 			XMLConstHandle docH( doc );
1630 			const XMLElement* ele = docH.FirstChildElement( "noSuchElement" ).FirstChildElement( "element" ).ToElement();
1631 			XMLTest( "Handle, const, element not found", true, ele == 0 );
1632 		}
1633 	}
1634 	{
1635 		// Default Declaration & BOM
1636 		XMLDocument doc;
1637 		doc.InsertEndChild( doc.NewDeclaration() );
1638 		doc.SetBOM( true );
1639 
1640 		XMLPrinter printer;
1641 		doc.Print( &printer );
1642 
1643 		static const char* result  = "\xef\xbb\xbf<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
1644 		XMLTest( "BOM and default declaration", result, printer.CStr(), false );
1645 		XMLTest( "CStrSize", 42, printer.CStrSize(), false );
1646 	}
1647 	{
1648 		const char* xml = "<ipxml ws='1'><info bla=' /></ipxml>";
1649 		XMLDocument doc;
1650 		doc.Parse( xml );
1651 		XMLTest( "Ill formed XML", true, doc.Error() );
1652 	}
1653 
1654     {
1655         //API:IntText(),UnsignedText(),Int64Text(),DoubleText(),BoolText() and FloatText() test
1656         const char* xml = "<point> <IntText>-24</IntText> <UnsignedText>42</UnsignedText> \
1657 						   <Int64Text>38</Int64Text> <BoolText>true</BoolText> <DoubleText>2.35</DoubleText> </point>";
1658         XMLDocument doc;
1659         doc.Parse(xml);
1660 
1661         const XMLElement* pointElement = doc.RootElement();
1662         int test1 = pointElement->FirstChildElement("IntText")->IntText();
1663         XMLTest("IntText() test", -24, test1);
1664 
1665         unsigned test2 = pointElement->FirstChildElement("UnsignedText")->UnsignedText();
1666         XMLTest("UnsignedText() test", static_cast<unsigned>(42), test2);
1667 
1668         int64_t test3 = pointElement->FirstChildElement("Int64Text")->Int64Text();
1669         XMLTest("Int64Text() test", static_cast<int64_t>(38), test3);
1670 
1671         double test4 = pointElement->FirstChildElement("DoubleText")->DoubleText();
1672         XMLTest("DoubleText() test", 2.35, test4);
1673 
1674         float test5 = pointElement->FirstChildElement("DoubleText")->FloatText();
1675         XMLTest("FloatText()) test", 2.35f, test5);
1676 
1677         bool test6 = pointElement->FirstChildElement("BoolText")->BoolText();
1678         XMLTest("FloatText()) test", true, test6);
1679     }
1680 
1681     {
1682         // hex value test
1683         const char* xml = "<point> <IntText>  0x2020</IntText> <UnsignedText>0X2020</UnsignedText> \
1684 						   <Int64Text> 0x1234</Int64Text></point>";
1685         XMLDocument doc;
1686         doc.Parse(xml);
1687 
1688         const XMLElement* pointElement = doc.RootElement();
1689         int test1 = pointElement->FirstChildElement("IntText")->IntText();
1690         XMLTest("IntText() hex value test", 0x2020, test1);
1691 
1692         unsigned test2 = pointElement->FirstChildElement("UnsignedText")->UnsignedText();
1693         XMLTest("UnsignedText() hex value test", static_cast<unsigned>(0x2020), test2);
1694 
1695         int64_t test3 = pointElement->FirstChildElement("Int64Text")->Int64Text();
1696         XMLTest("Int64Text() hex value test", static_cast<int64_t>(0x1234), test3);
1697     }
1698 
1699 	{
1700 		//API:ShallowEqual() test
1701 		const char* xml = "<playlist id = 'playlist'>"
1702 						    "<property name = 'track_name'>voice</property>"
1703 						  "</playlist>";
1704 		XMLDocument doc;
1705 		doc.Parse( xml );
1706 		const XMLNode* PlaylistNode = doc.RootElement();
1707 		const XMLNode* PropertyNode = PlaylistNode->FirstChildElement();
1708 		bool result;
1709 		result = PlaylistNode->ShallowEqual(PropertyNode);
1710 		XMLTest("ShallowEqual() test",false,result);
1711 		result = PlaylistNode->ShallowEqual(PlaylistNode);
1712 		XMLTest("ShallowEqual() test",true,result);
1713 	}
1714 
1715 	{
1716 		//API: previousSiblingElement() and NextSiblingElement() test
1717 		const char* xml = "<playlist id = 'playlist'>"
1718 						    "<property name = 'track_name'>voice</property>"
1719 						    "<entry out = '946' producer = '2_playlist1' in = '0'/>"
1720 							"<blank length = '1'/>"
1721 						  "</playlist>";
1722 		XMLDocument doc;
1723 		doc.Parse( xml );
1724 		XMLElement* ElementPlaylist = doc.FirstChildElement("playlist");
1725 		XMLTest("previousSiblingElement() test",true,ElementPlaylist != 0);
1726 		const XMLElement* pre = ElementPlaylist->PreviousSiblingElement();
1727 		XMLTest("previousSiblingElement() test",true,pre == 0);
1728 		const XMLElement* ElementBlank = ElementPlaylist->FirstChildElement("entry")->NextSiblingElement("blank");
1729 		XMLTest("NextSiblingElement() test",true,ElementBlank != 0);
1730 		const XMLElement* next = ElementBlank->NextSiblingElement();
1731 		XMLTest("NextSiblingElement() test",true,next == 0);
1732 		const XMLElement* ElementEntry = ElementBlank->PreviousSiblingElement("entry");
1733 		XMLTest("PreviousSiblingElement test",true,ElementEntry != 0);
1734 	}
1735 
1736 	// QueryXYZText
1737 	{
1738 		const char* xml = "<point> <x>1.2</x> <y>1</y> <z>38</z> <valid>true</valid> </point>";
1739 		XMLDocument doc;
1740 		doc.Parse( xml );
1741 		XMLTest( "Parse points", false, doc.Error() );
1742 
1743 		const XMLElement* pointElement = doc.RootElement();
1744 
1745 		{
1746 			int intValue = 0;
1747 			XMLError queryResult = pointElement->FirstChildElement( "y" )->QueryIntText( &intValue );
1748 			XMLTest( "QueryIntText result", XML_SUCCESS, queryResult, false );
1749 			XMLTest( "QueryIntText", 1, intValue, false );
1750 		}
1751 
1752 		{
1753 			unsigned unsignedValue = 0;
1754 			XMLError queryResult = pointElement->FirstChildElement( "y" )->QueryUnsignedText( &unsignedValue );
1755 			XMLTest( "QueryUnsignedText result", XML_SUCCESS, queryResult, false );
1756 			XMLTest( "QueryUnsignedText", (unsigned)1, unsignedValue, false );
1757 		}
1758 
1759 		{
1760 			float floatValue = 0;
1761 			XMLError queryResult = pointElement->FirstChildElement( "x" )->QueryFloatText( &floatValue );
1762 			XMLTest( "QueryFloatText result", XML_SUCCESS, queryResult, false );
1763 			XMLTest( "QueryFloatText", 1.2f, floatValue, false );
1764 		}
1765 
1766 		{
1767 			double doubleValue = 0;
1768 			XMLError queryResult = pointElement->FirstChildElement( "x" )->QueryDoubleText( &doubleValue );
1769 			XMLTest( "QueryDoubleText result", XML_SUCCESS, queryResult, false );
1770 			XMLTest( "QueryDoubleText", 1.2, doubleValue, false );
1771 		}
1772 
1773 		{
1774 			bool boolValue = false;
1775 			XMLError queryResult = pointElement->FirstChildElement( "valid" )->QueryBoolText( &boolValue );
1776 			XMLTest( "QueryBoolText result", XML_SUCCESS, queryResult, false );
1777 			XMLTest( "QueryBoolText", true, boolValue, false );
1778 		}
1779 	}
1780 
1781 	{
1782 		const char* xml = "<element><_sub/><:sub/><sub:sub/><sub-sub/></element>";
1783 		XMLDocument doc;
1784 		doc.Parse( xml );
1785 		XMLTest( "Non-alpha element lead letter parses.", false, doc.Error() );
1786 	}
1787 
1788     {
1789         const char* xml = "<element _attr1=\"foo\" :attr2=\"bar\"></element>";
1790         XMLDocument doc;
1791         doc.Parse( xml );
1792         XMLTest("Non-alpha attribute lead character parses.", false, doc.Error());
1793     }
1794 
1795     {
1796         const char* xml = "<3lement></3lement>";
1797         XMLDocument doc;
1798         doc.Parse( xml );
1799         XMLTest("Element names with lead digit fail to parse.", true, doc.Error());
1800     }
1801 
1802 	{
1803 		const char* xml = "<element/>WOA THIS ISN'T GOING TO PARSE";
1804 		XMLDocument doc;
1805 		doc.Parse( xml, 10 );
1806 		XMLTest( "Set length of incoming data", false, doc.Error() );
1807 	}
1808 
1809     {
1810         XMLDocument doc;
1811         XMLTest( "Document is initially empty", true, doc.NoChildren() );
1812         doc.Clear();
1813         XMLTest( "Empty is empty after Clear()", true, doc.NoChildren() );
1814         doc.LoadFile( "resources/dream.xml" );
1815         XMLTest( "Load dream.xml", false, doc.Error() );
1816         XMLTest( "Document has something to Clear()", false, doc.NoChildren() );
1817         doc.Clear();
1818         XMLTest( "Document Clear()'s", true, doc.NoChildren() );
1819     }
1820 
1821     {
1822         XMLDocument doc;
1823         XMLTest( "No error initially", false, doc.Error() );
1824         XMLError error = doc.Parse( "This is not XML" );
1825         XMLTest( "Error after invalid XML", true, doc.Error() );
1826         XMLTest( "Error after invalid XML", error, doc.ErrorID() );
1827         doc.Clear();
1828         XMLTest( "No error after Clear()", false, doc.Error() );
1829     }
1830 
1831 	// ----------- Whitespace ------------
1832 	{
1833 		const char* xml = "<element>"
1834 							"<a> This \nis &apos;  text  &apos; </a>"
1835 							"<b>  This is &apos; text &apos;  \n</b>"
1836 							"<c>This  is  &apos;  \n\n text &apos;</c>"
1837 						  "</element>";
1838 		XMLDocument doc( true, COLLAPSE_WHITESPACE );
1839 		doc.Parse( xml );
1840 		XMLTest( "Parse with whitespace collapsing and &apos", false, doc.Error() );
1841 
1842 		const XMLElement* element = doc.FirstChildElement();
1843 		for( const XMLElement* parent = element->FirstChildElement();
1844 			 parent;
1845 			 parent = parent->NextSiblingElement() )
1846 		{
1847 			XMLTest( "Whitespace collapse", "This is ' text '", parent->GetText() );
1848 		}
1849 	}
1850 
1851 #if 0
1852 	{
1853 		// Passes if assert doesn't fire.
1854 		XMLDocument xmlDoc;
1855 
1856 	    xmlDoc.NewDeclaration();
1857 	    xmlDoc.NewComment("Configuration file");
1858 
1859 	    XMLElement *root = xmlDoc.NewElement("settings");
1860 	    root->SetAttribute("version", 2);
1861 	}
1862 #endif
1863 
1864 	{
1865 		const char* xml = "<element>    </element>";
1866 		XMLDocument doc( true, COLLAPSE_WHITESPACE );
1867 		doc.Parse( xml );
1868 		XMLTest( "Parse with all whitespaces", false, doc.Error() );
1869 		XMLTest( "Whitespace  all space", true, 0 == doc.FirstChildElement()->FirstChild() );
1870 	}
1871 
1872 	{
1873 		// An assert should not fire.
1874 		const char* xml = "<element/>";
1875 		XMLDocument doc;
1876 		doc.Parse( xml );
1877 		XMLTest( "Parse with self-closed element", false, doc.Error() );
1878 		XMLElement* ele = doc.NewElement( "unused" );		// This will get cleaned up with the 'doc' going out of scope.
1879 		XMLTest( "Tracking unused elements", true, ele != 0, false );
1880 	}
1881 
1882 
1883 	{
1884 		const char* xml = "<parent><child>abc</child></parent>";
1885 		XMLDocument doc;
1886 		doc.Parse( xml );
1887 		XMLTest( "Parse for printing of sub-element", false, doc.Error() );
1888 		XMLElement* ele = doc.FirstChildElement( "parent")->FirstChildElement( "child");
1889 
1890 		XMLPrinter printer;
1891 		bool acceptResult = ele->Accept( &printer );
1892 		XMLTest( "Accept of sub-element", true, acceptResult );
1893 		XMLTest( "Printing of sub-element", "<child>abc</child>\n", printer.CStr(), false );
1894 	}
1895 
1896 
1897 	{
1898 		XMLDocument doc;
1899 		XMLError error = doc.LoadFile( "resources/empty.xml" );
1900 		XMLTest( "Loading an empty file", XML_ERROR_EMPTY_DOCUMENT, error );
1901 		XMLTest( "Loading an empty file and ErrorName as string", "XML_ERROR_EMPTY_DOCUMENT", doc.ErrorName() );
1902 		doc.PrintError();
1903 	}
1904 
1905 	{
1906         // BOM preservation
1907         static const char* xml_bom_preservation  = "\xef\xbb\xbf<element/>\n";
1908         {
1909 			XMLDocument doc;
1910 			XMLTest( "BOM preservation (parse)", XML_SUCCESS, doc.Parse( xml_bom_preservation ), false );
1911             XMLPrinter printer;
1912             doc.Print( &printer );
1913 
1914             XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1915 			doc.SaveFile( "resources/out/bomtest.xml" );
1916 			XMLTest( "Save bomtest.xml", false, doc.Error() );
1917         }
1918 		{
1919 			XMLDocument doc;
1920 			doc.LoadFile( "resources/out/bomtest.xml" );
1921 			XMLTest( "Load bomtest.xml", false, doc.Error() );
1922 			XMLTest( "BOM preservation (load)", true, doc.HasBOM(), false );
1923 
1924             XMLPrinter printer;
1925             doc.Print( &printer );
1926             XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1927 		}
1928 	}
1929 
1930 	{
1931 		// Insertion with Removal
1932 		const char* xml = "<?xml version=\"1.0\" ?>"
1933 			"<root>"
1934 			"<one>"
1935 			"<subtree>"
1936 			"<elem>element 1</elem>text<!-- comment -->"
1937 			"</subtree>"
1938 			"</one>"
1939 			"<two/>"
1940 			"</root>";
1941 		const char* xmlInsideTwo = "<?xml version=\"1.0\" ?>"
1942 			"<root>"
1943 			"<one/>"
1944 			"<two>"
1945 			"<subtree>"
1946 			"<elem>element 1</elem>text<!-- comment -->"
1947 			"</subtree>"
1948 			"</two>"
1949 			"</root>";
1950 		const char* xmlAfterOne = "<?xml version=\"1.0\" ?>"
1951 			"<root>"
1952 			"<one/>"
1953 			"<subtree>"
1954 			"<elem>element 1</elem>text<!-- comment -->"
1955 			"</subtree>"
1956 			"<two/>"
1957 			"</root>";
1958 		const char* xmlAfterTwo = "<?xml version=\"1.0\" ?>"
1959 			"<root>"
1960 			"<one/>"
1961 			"<two/>"
1962 			"<subtree>"
1963 			"<elem>element 1</elem>text<!-- comment -->"
1964 			"</subtree>"
1965 			"</root>";
1966 
1967 		XMLDocument doc;
1968 		doc.Parse(xml);
1969 		XMLTest( "Insertion with removal parse round 1", false, doc.Error() );
1970 		XMLElement* subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1971 		XMLElement* two = doc.RootElement()->FirstChildElement("two");
1972 		two->InsertFirstChild(subtree);
1973 		XMLPrinter printer1(0, true);
1974 		bool acceptResult = doc.Accept(&printer1);
1975 		XMLTest("Move node from within <one> to <two> - Accept()", true, acceptResult);
1976 		XMLTest("Move node from within <one> to <two>", xmlInsideTwo, printer1.CStr());
1977 
1978 		doc.Parse(xml);
1979 		XMLTest( "Insertion with removal parse round 2", false, doc.Error() );
1980 		subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1981 		two = doc.RootElement()->FirstChildElement("two");
1982 		doc.RootElement()->InsertAfterChild(two, subtree);
1983 		XMLPrinter printer2(0, true);
1984 		acceptResult = doc.Accept(&printer2);
1985 		XMLTest("Move node from within <one> after <two> - Accept()", true, acceptResult);
1986 		XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer2.CStr(), false);
1987 
1988 		doc.Parse(xml);
1989 		XMLTest( "Insertion with removal parse round 3", false, doc.Error() );
1990 		XMLNode* one = doc.RootElement()->FirstChildElement("one");
1991 		subtree = one->FirstChildElement("subtree");
1992 		doc.RootElement()->InsertAfterChild(one, subtree);
1993 		XMLPrinter printer3(0, true);
1994 		acceptResult = doc.Accept(&printer3);
1995 		XMLTest("Move node from within <one> after <one> - Accept()", true, acceptResult);
1996 		XMLTest("Move node from within <one> after <one>", xmlAfterOne, printer3.CStr(), false);
1997 
1998 		doc.Parse(xml);
1999 		XMLTest( "Insertion with removal parse round 4", false, doc.Error() );
2000 		subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
2001 		two = doc.RootElement()->FirstChildElement("two");
2002 		XMLTest("<two> is the last child at root level", true, two == doc.RootElement()->LastChildElement());
2003 		doc.RootElement()->InsertEndChild(subtree);
2004 		XMLPrinter printer4(0, true);
2005 		acceptResult = doc.Accept(&printer4);
2006 		XMLTest("Move node from within <one> after <two> - Accept()", true, acceptResult);
2007 		XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer4.CStr(), false);
2008 	}
2009 
2010 	{
2011 		const char* xml = "<svg width = \"128\" height = \"128\">"
2012 			"	<text> </text>"
2013 			"</svg>";
2014 		XMLDocument doc;
2015 		doc.Parse(xml);
2016 		XMLTest( "Parse svg with text", false, doc.Error() );
2017 		doc.Print();
2018 	}
2019 
2020 	{
2021 		// Test that it doesn't crash.
2022 		const char* xml = "<?xml version=\"1.0\"?><root><sample><field0><1</field0><field1>2</field1></sample></root>";
2023 		XMLDocument doc;
2024 		doc.Parse(xml);
2025 		XMLTest( "Parse root-sample-field0", true, doc.Error() );
2026 		doc.PrintError();
2027 	}
2028 
2029 #if 1
2030 		// the question being explored is what kind of print to use:
2031 		// https://github.com/leethomason/tinyxml2/issues/63
2032 	{
2033 		//const char* xml = "<element attrA='123456789.123456789' attrB='1.001e9' attrC='1.0e-10' attrD='1001000000.000000' attrE='0.1234567890123456789'/>";
2034 		const char* xml = "<element/>";
2035 		XMLDocument doc;
2036 		doc.Parse( xml );
2037 		XMLTest( "Parse self-closed empty element", false, doc.Error() );
2038 		doc.FirstChildElement()->SetAttribute( "attrA-f64", 123456789.123456789 );
2039 		doc.FirstChildElement()->SetAttribute( "attrB-f64", 1.001e9 );
2040 		doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e9 );
2041 		doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e20 );
2042 		doc.FirstChildElement()->SetAttribute( "attrD-f64", 1.0e-10 );
2043 		doc.FirstChildElement()->SetAttribute( "attrD-f64", 0.123456789 );
2044 
2045 		doc.FirstChildElement()->SetAttribute( "attrA-f32", 123456789.123456789f );
2046 		doc.FirstChildElement()->SetAttribute( "attrB-f32", 1.001e9f );
2047 		doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e9f );
2048 		doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e20f );
2049 		doc.FirstChildElement()->SetAttribute( "attrD-f32", 1.0e-10f );
2050 		doc.FirstChildElement()->SetAttribute( "attrD-f32", 0.123456789f );
2051 
2052 		doc.Print();
2053 
2054 		/* The result of this test is platform, compiler, and library version dependent. :("
2055 		XMLPrinter printer;
2056 		doc.Print( &printer );
2057 		XMLTest( "Float and double formatting.",
2058 			"<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",
2059 			printer.CStr(),
2060 			true );
2061 		*/
2062 	}
2063 #endif
2064 
2065     {
2066         // Issue #184
2067         // If it doesn't assert, it passes. Caused by objects
2068         // getting created during parsing which are then
2069         // inaccessible in the memory pools.
2070         const char* xmlText = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><test>";
2071         {
2072             XMLDocument doc;
2073             doc.Parse(xmlText);
2074             XMLTest( "Parse hex no closing tag round 1", true, doc.Error() );
2075         }
2076         {
2077             XMLDocument doc;
2078             doc.Parse(xmlText);
2079             XMLTest( "Parse hex no closing tag round 2", true, doc.Error() );
2080             doc.Clear();
2081         }
2082     }
2083 
2084     {
2085         // If this doesn't assert in TINYXML2_DEBUG, all is well.
2086         tinyxml2::XMLDocument doc;
2087         tinyxml2::XMLElement *pRoot = doc.NewElement("Root");
2088         doc.DeleteNode(pRoot);
2089     }
2090 
2091     {
2092         XMLDocument doc;
2093         XMLElement* root = doc.NewElement( "Root" );
2094         XMLTest( "Node document before insertion", true, &doc == root->GetDocument() );
2095         doc.InsertEndChild( root );
2096         XMLTest( "Node document after insertion", true, &doc == root->GetDocument() );
2097     }
2098 
2099     {
2100         // If this doesn't assert in TINYXML2_DEBUG, all is well.
2101         XMLDocument doc;
2102         XMLElement* unlinkedRoot = doc.NewElement( "Root" );
2103         XMLElement* linkedRoot = doc.NewElement( "Root" );
2104         doc.InsertFirstChild( linkedRoot );
2105         unlinkedRoot->GetDocument()->DeleteNode( linkedRoot );
2106         unlinkedRoot->GetDocument()->DeleteNode( unlinkedRoot );
2107     }
2108 
2109 	{
2110 		// Should not assert in TINYXML2_DEBUG
2111 		XMLPrinter printer;
2112 	}
2113 
2114 	{
2115 		// Issue 291. Should not crash
2116 		const char* xml = "&#0</a>";
2117 		XMLDocument doc;
2118 		doc.Parse( xml );
2119 		XMLTest( "Parse hex with closing tag", false, doc.Error() );
2120 
2121 		XMLPrinter printer;
2122 		doc.Print( &printer );
2123 	}
2124 	{
2125 		// Issue 299. Can print elements that are not linked in.
2126 		// Will crash if issue not fixed.
2127 		XMLDocument doc;
2128 		XMLElement* newElement = doc.NewElement( "printme" );
2129 		XMLPrinter printer;
2130 		bool acceptResult = newElement->Accept( &printer );
2131 		XMLTest( "printme - Accept()", true, acceptResult );
2132 		// Delete the node to avoid possible memory leak report in debug output
2133 		doc.DeleteNode( newElement );
2134 	}
2135 	{
2136 		// Issue 302. Clear errors from LoadFile/SaveFile
2137 		XMLDocument doc;
2138 		XMLTest( "Issue 302. Should be no error initially", "XML_SUCCESS", doc.ErrorName() );
2139 		doc.SaveFile( "./no/such/path/pretty.xml" );
2140 		XMLTest( "Issue 302. Fail to save", "XML_ERROR_FILE_COULD_NOT_BE_OPENED", doc.ErrorName() );
2141 		doc.SaveFile( "./resources/out/compact.xml", true );
2142 		XMLTest( "Issue 302. Subsequent success in saving", "XML_SUCCESS", doc.ErrorName() );
2143 	}
2144 
2145 	{
2146 		// If a document fails to load then subsequent
2147 		// successful loads should clear the error
2148 		XMLDocument doc;
2149 		XMLTest( "Should be no error initially", false, doc.Error() );
2150 		doc.LoadFile( "resources/no-such-file.xml" );
2151 		XMLTest( "No such file - should fail", true, doc.Error() );
2152 
2153 		doc.LoadFile( "resources/dream.xml" );
2154 		XMLTest( "Error should be cleared", false, doc.Error() );
2155 	}
2156 
2157 	{
2158 		// Check that declarations are allowed only at beginning of document
2159 	    const char* xml0 = "<?xml version=\"1.0\" ?>"
2160 	                       "   <!-- xml version=\"1.1\" -->"
2161 	                       "<first />";
2162 	    const char* xml1 = "<?xml version=\"1.0\" ?>"
2163 	                       "<?xml-stylesheet type=\"text/xsl\" href=\"Anything.xsl\"?>"
2164 	                       "<first />";
2165 	    const char* xml2 = "<first />"
2166 	                       "<?xml version=\"1.0\" ?>";
2167 	    const char* xml3 = "<first></first>"
2168 	                       "<?xml version=\"1.0\" ?>";
2169 
2170 	    const char* xml4 = "<first><?xml version=\"1.0\" ?></first>";
2171 
2172 	    XMLDocument doc;
2173 	    doc.Parse(xml0);
2174 	    XMLTest("Test that the code changes do not affect normal parsing", false, doc.Error() );
2175 	    doc.Parse(xml1);
2176 	    XMLTest("Test that the second declaration is allowed", false, doc.Error() );
2177 	    doc.Parse(xml2);
2178 	    XMLTest("Test that declaration after self-closed child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
2179 	    doc.Parse(xml3);
2180 	    XMLTest("Test that declaration after a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
2181 	    doc.Parse(xml4);
2182 	    XMLTest("Test that declaration inside a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
2183 	}
2184 
2185     {
2186 	    // No matter - before or after successfully parsing a text -
2187 	    // calling XMLDocument::Value() used to cause an assert in debug.
2188 	    // Null must be returned.
2189 	    const char* validXml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
2190 	                           "<first />"
2191 	                           "<second />";
2192 	    XMLDocument* doc = new XMLDocument();
2193 	    XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
2194 	    doc->Parse( validXml );
2195 	    XMLTest( "Parse to test XMLDocument::Value()", false, doc->Error());
2196 	    XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
2197 	    delete doc;
2198     }
2199 
2200 	{
2201 		XMLDocument doc;
2202 		for( int i = 0; i < XML_ERROR_COUNT; i++ ) {
2203 			const XMLError error = static_cast<XMLError>(i);
2204 			const char* name = XMLDocument::ErrorIDToName(error);
2205 			XMLTest( "ErrorName() not null after ClearError()", true, name != 0 );
2206 			if( name == 0 ) {
2207 				// passing null pointer into strlen() is undefined behavior, so
2208 				// compiler is allowed to optimise away the null test above if it's
2209 				// as reachable as the strlen() call
2210 				continue;
2211 			}
2212 			XMLTest( "ErrorName() not empty after ClearError()", true, strlen(name) > 0 );
2213 		}
2214 	}
2215 
2216 	{
2217 		const char* html("<!DOCTYPE html><html><body><p>test</p><p><br/></p></body></html>");
2218 		XMLDocument doc(false);
2219 		doc.Parse(html);
2220 
2221 		XMLPrinter printer(0, true);
2222 		doc.Print(&printer);
2223 
2224 		XMLTest(html, html, printer.CStr());
2225 	}
2226 
2227 	{
2228 		// Evil memory leaks.
2229 		// If an XMLElement (etc) is allocated via NewElement() (etc.)
2230 		// and NOT added to the XMLDocument, what happens?
2231 		//
2232 		// Previously (buggy):
2233 		//		The memory would be free'd when the XMLDocument is
2234 		//      destructed. But the XMLElement destructor wasn't called, so
2235 		//      memory allocated for the XMLElement text would not be free'd.
2236 		//      In practice this meant strings allocated for the XMLElement
2237 		//      text would be leaked. An edge case, but annoying.
2238 		// Now:
2239 		//      The XMLElement destructor is called. But the unlinked nodes
2240 		//      have to be tracked using a list. This has a minor performance
2241 		//      impact that can become significant if you have a lot of
2242 		//      unlinked nodes. (But why would you do that?)
2243 		// The only way to see this bug was in a Visual C++ runtime debug heap
2244 		// leak tracker. This is compiled in by default on Windows Debug and
2245 		// enabled with _CRTDBG_LEAK_CHECK_DF parameter passed to _CrtSetDbgFlag().
2246 		{
2247 			XMLDocument doc;
2248 			doc.NewElement("LEAK 1");
2249 		}
2250 		{
2251 			XMLDocument doc;
2252 			XMLElement* ele = doc.NewElement("LEAK 2");
2253 			doc.DeleteNode(ele);
2254 		}
2255 	}
2256 
2257 	{
2258 		// Bad bad crash. Parsing error results in stack overflow, if uncaught.
2259 		const char* TESTS[] = {
2260 			"./resources/xmltest-5330.xml",
2261 			"./resources/xmltest-4636783552757760.xml",
2262 			"./resources/xmltest-5720541257269248.xml",
2263 			0
2264 		};
2265 		for (int i=0; TESTS[i]; ++i) {
2266 			XMLDocument doc;
2267 			doc.LoadFile(TESTS[i]);
2268 			XMLTest("Stack overflow prevented.", XML_ELEMENT_DEPTH_EXCEEDED, doc.ErrorID());
2269 		}
2270 	}
2271     {
2272         const char* TESTS[] = {
2273             "./resources/xmltest-5662204197076992.xml",     // Security-level performance issue.
2274             0
2275         };
2276         for (int i = 0; TESTS[i]; ++i) {
2277             XMLDocument doc;
2278             doc.LoadFile(TESTS[i]);
2279             // Need only not crash / lock up.
2280             XMLTest("Fuzz attack prevented.", true, true);
2281         }
2282     }
2283 	{
2284 		// Crashing reported via email.
2285 		const char* xml =
2286 			"<playlist id='playlist1'>"
2287 			"<property name='track_name'>voice</property>"
2288 			"<property name='audio_track'>1</property>"
2289 			"<entry out = '604' producer = '4_playlist1' in = '0' />"
2290 			"<blank length = '1' />"
2291 			"<entry out = '1625' producer = '3_playlist' in = '0' />"
2292 			"<blank length = '2' />"
2293 			"<entry out = '946' producer = '2_playlist1' in = '0' />"
2294 			"<blank length = '1' />"
2295 			"<entry out = '128' producer = '1_playlist1' in = '0' />"
2296 			"</playlist>";
2297 
2298 		// It's not a good idea to delete elements as you walk the
2299 		// list. I'm not sure this technically should work; but it's
2300 		// an interesting test case.
2301 		XMLDocument doc;
2302 		XMLError err = doc.Parse(xml);
2303 		XMLTest("Crash bug parsing", XML_SUCCESS, err );
2304 
2305 		XMLElement* playlist = doc.FirstChildElement("playlist");
2306 		XMLTest("Crash bug parsing", true, playlist != 0);
2307 
2308 		{
2309 			const char* elementName = "entry";
2310 			XMLElement* entry = playlist->FirstChildElement(elementName);
2311 			XMLTest("Crash bug parsing", true, entry != 0);
2312 			while (entry) {
2313 				XMLElement* todelete = entry;
2314 				entry = entry->NextSiblingElement(elementName);
2315 				playlist->DeleteChild(todelete);
2316 			}
2317 			entry = playlist->FirstChildElement(elementName);
2318 			XMLTest("Crash bug parsing", true, entry == 0);
2319 		}
2320 		{
2321 			const char* elementName = "blank";
2322 			XMLElement* blank = playlist->FirstChildElement(elementName);
2323 			XMLTest("Crash bug parsing", true, blank != 0);
2324 			while (blank) {
2325 				XMLElement* todelete = blank;
2326 				blank = blank->NextSiblingElement(elementName);
2327 				playlist->DeleteChild(todelete);
2328 			}
2329 			XMLTest("Crash bug parsing", true, blank == 0);
2330 		}
2331 
2332 		tinyxml2::XMLPrinter printer;
2333 		const bool acceptResult = playlist->Accept(&printer);
2334 		XMLTest("Crash bug parsing - Accept()", true, acceptResult);
2335 		printf("%s\n", printer.CStr());
2336 
2337 		// No test; it only need to not crash.
2338 		// Still, wrap it up with a sanity check
2339 		int nProperty = 0;
2340 		for (const XMLElement* p = playlist->FirstChildElement("property"); p; p = p->NextSiblingElement("property")) {
2341 			nProperty++;
2342 		}
2343 		XMLTest("Crash bug parsing", 2, nProperty);
2344 	}
2345 
2346     // ----------- Line Number Tracking --------------
2347     {
2348         struct TestUtil: XMLVisitor
2349         {
2350             TestUtil() : str() {}
2351 
2352             void TestParseError(const char *testString, const char *docStr, XMLError expected_error, int expectedLine)
2353             {
2354                 XMLDocument doc;
2355                 const XMLError parseError = doc.Parse(docStr);
2356 
2357                 XMLTest(testString, parseError, doc.ErrorID());
2358                 XMLTest(testString, true, doc.Error());
2359                 XMLTest(testString, expected_error, parseError);
2360                 XMLTest(testString, expectedLine, doc.ErrorLineNum());
2361             };
2362 
2363             void TestStringLines(const char *testString, const char *docStr, const char *expectedLines)
2364             {
2365                 XMLDocument doc;
2366                 doc.Parse(docStr);
2367                 XMLTest(testString, false, doc.Error());
2368                 TestDocLines(testString, doc, expectedLines);
2369             }
2370 
2371             void TestFileLines(const char *testString, const char *file_name, const char *expectedLines)
2372             {
2373                 XMLDocument doc;
2374                 doc.LoadFile(file_name);
2375                 XMLTest(testString, false, doc.Error());
2376                 TestDocLines(testString, doc, expectedLines);
2377             }
2378 
2379         private:
2380             DynArray<char, 10> str;
2381 
2382             void Push(char type, int lineNum)
2383             {
2384                 str.Push(type);
2385                 str.Push(char('0' + (lineNum / 10)));
2386                 str.Push(char('0' + (lineNum % 10)));
2387             }
2388 
2389             bool VisitEnter(const XMLDocument& doc)
2390             {
2391                 Push('D', doc.GetLineNum());
2392                 return true;
2393             }
2394             bool VisitEnter(const XMLElement& element, const XMLAttribute* firstAttribute)
2395             {
2396                 Push('E', element.GetLineNum());
2397                 for (const XMLAttribute *attr = firstAttribute; attr != 0; attr = attr->Next())
2398                     Push('A', attr->GetLineNum());
2399                 return true;
2400             }
2401             bool Visit(const XMLDeclaration& declaration)
2402             {
2403                 Push('L', declaration.GetLineNum());
2404                 return true;
2405             }
2406             bool Visit(const XMLText& text)
2407             {
2408                 Push('T', text.GetLineNum());
2409                 return true;
2410             }
2411             bool Visit(const XMLComment& comment)
2412             {
2413                 Push('C', comment.GetLineNum());
2414                 return true;
2415             }
2416             bool Visit(const XMLUnknown& unknown)
2417             {
2418                 Push('U', unknown.GetLineNum());
2419                 return true;
2420             }
2421 
2422             void TestDocLines(const char *testString, XMLDocument &doc, const char *expectedLines)
2423             {
2424                 str.Clear();
2425                 const bool acceptResult = doc.Accept(this);
2426                 XMLTest(testString, true, acceptResult);
2427                 str.Push(0);
2428                 XMLTest(testString, expectedLines, str.Mem());
2429             }
2430         } tester;
2431 
2432 		tester.TestParseError("ErrorLine-Parsing", "\n<root>\n foo \n<unclosed/>", XML_ERROR_PARSING, 2);
2433         tester.TestParseError("ErrorLine-Declaration", "<root>\n<?xml version=\"1.0\"?>", XML_ERROR_PARSING_DECLARATION, 2);
2434         tester.TestParseError("ErrorLine-Mismatch", "\n<root>\n</mismatch>", XML_ERROR_MISMATCHED_ELEMENT, 2);
2435         tester.TestParseError("ErrorLine-CData", "\n<root><![CDATA[ \n foo bar \n", XML_ERROR_PARSING_CDATA, 2);
2436         tester.TestParseError("ErrorLine-Text", "\n<root>\n foo bar \n", XML_ERROR_PARSING_TEXT, 3);
2437         tester.TestParseError("ErrorLine-Comment", "\n<root>\n<!-- >\n", XML_ERROR_PARSING_COMMENT, 3);
2438         tester.TestParseError("ErrorLine-Declaration", "\n<root>\n<? >\n", XML_ERROR_PARSING_DECLARATION, 3);
2439         tester.TestParseError("ErrorLine-Unknown", "\n<root>\n<! \n", XML_ERROR_PARSING_UNKNOWN, 3);
2440         tester.TestParseError("ErrorLine-Element", "\n<root>\n<unclosed \n", XML_ERROR_PARSING_ELEMENT, 3);
2441         tester.TestParseError("ErrorLine-Attribute", "\n<root>\n<unclosed \n att\n", XML_ERROR_PARSING_ATTRIBUTE, 4);
2442         tester.TestParseError("ErrorLine-ElementClose", "\n<root>\n<unclosed \n/unexpected", XML_ERROR_PARSING_ELEMENT, 3);
2443 
2444 		tester.TestStringLines(
2445             "LineNumbers-String",
2446 
2447             "<?xml version=\"1.0\"?>\n"					// 1 Doc, DecL
2448                 "<root a='b' \n"						// 2 Element Attribute
2449                 "c='d'> d <blah/>  \n"					// 3 Attribute Text Element
2450                 "newline in text \n"					// 4 Text
2451                 "and second <zxcv/><![CDATA[\n"			// 5 Element Text
2452                 " cdata test ]]><!-- comment -->\n"		// 6 Comment
2453                 "<! unknown></root>",					// 7 Unknown
2454 
2455             "D01L01E02A02A03T03E03T04E05T05C06U07");
2456 
2457 		tester.TestStringLines(
2458             "LineNumbers-CRLF",
2459 
2460             "\r\n"										// 1 Doc (arguably should be line 2)
2461             "<?xml version=\"1.0\"?>\n"					// 2 DecL
2462             "<root>\r\n"								// 3 Element
2463             "\n"										// 4
2464             "text contining new line \n"				// 5 Text
2465             " and also containing crlf \r\n"			// 6
2466             "<sub><![CDATA[\n"							// 7 Element Text
2467             "cdata containing new line \n"				// 8
2468             " and also containing cflr\r\n"				// 9
2469             "]]></sub><sub2/></root>",					// 10 Element
2470 
2471             "D01L02E03T05E07T07E10");
2472 
2473 		tester.TestFileLines(
2474             "LineNumbers-File",
2475             "resources/utf8test.xml",
2476             "D01L01E02E03A03A03T03E04A04A04T04E05A05A05T05E06A06A06T06E07A07A07T07E08A08A08T08E09T09E10T10");
2477     }
2478 
2479     {
2480     	const char* xml = "<Hello>Text</Error>";
2481     	XMLDocument doc;
2482     	doc.Parse(xml);
2483     	XMLTest("Test mismatched elements.", true, doc.Error());
2484     	XMLTest("Test mismatched elements.", XML_ERROR_MISMATCHED_ELEMENT, doc.ErrorID());
2485     	// For now just make sure calls work & doesn't crash.
2486     	// May solidify the error output in the future.
2487     	printf("%s\n", doc.ErrorStr());
2488     	doc.PrintError();
2489     }
2490 
2491     // ----------- Performance tracking --------------
2492 	{
2493 #if defined( _MSC_VER )
2494 		__int64 start, end, freq;
2495 		QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
2496 #endif
2497 
2498 		FILE* perfFP = fopen("resources/dream.xml", "r");
2499 		XMLTest("Open dream.xml", true, perfFP != 0);
2500 		fseek(perfFP, 0, SEEK_END);
2501 		long size = ftell(perfFP);
2502 		fseek(perfFP, 0, SEEK_SET);
2503 
2504 		char* mem = new char[size + 1];
2505 		memset(mem, 0xfe, size);
2506 		size_t bytesRead = fread(mem, 1, size, perfFP);
2507 		XMLTest("Read dream.xml", true, uint32_t(size) >= uint32_t(bytesRead));
2508 		fclose(perfFP);
2509 		mem[size] = 0;
2510 
2511 #if defined( _MSC_VER )
2512 		QueryPerformanceCounter((LARGE_INTEGER*)&start);
2513 #else
2514 		clock_t cstart = clock();
2515 #endif
2516 		bool parseDreamXmlFailed = false;
2517 		static const int COUNT = 10;
2518 		for (int i = 0; i < COUNT; ++i) {
2519 			XMLDocument doc;
2520 			doc.Parse(mem);
2521 			parseDreamXmlFailed = parseDreamXmlFailed || doc.Error();
2522 		}
2523 #if defined( _MSC_VER )
2524 		QueryPerformanceCounter((LARGE_INTEGER*)&end);
2525 #else
2526 		clock_t cend = clock();
2527 #endif
2528 		XMLTest( "Parse dream.xml", false, parseDreamXmlFailed );
2529 
2530 		delete[] mem;
2531 
2532 		static const char* note =
2533 #ifdef TINYXML2_DEBUG
2534 			"DEBUG";
2535 #else
2536 			"Release";
2537 #endif
2538 
2539 #if defined( _MSC_VER )
2540 		const double duration = 1000.0 * (double)(end - start) / ((double)freq * (double)COUNT);
2541 #else
2542 		const double duration = (double)(cend - cstart) / (double)COUNT;
2543 #endif
2544 		printf("\nParsing dream.xml (%s): %.3f milli-seconds\n", note, duration);
2545 	}
2546 
2547 #if defined( _MSC_VER ) &&  defined( TINYXML2_DEBUG )
2548 	{
2549 		_CrtMemCheckpoint( &endMemState );
2550 
2551 		_CrtMemState diffMemState;
2552 		_CrtMemDifference( &diffMemState, &startMemState, &endMemState );
2553 		_CrtMemDumpStatistics( &diffMemState );
2554 
2555 		{
2556 			int leaksBeforeExit = _CrtDumpMemoryLeaks();
2557 			XMLTest( "No leaks before exit?", FALSE, leaksBeforeExit );
2558 		}
2559 	}
2560 #endif
2561 
2562 	printf ("\nPass %d, Fail %d\n", gPass, gFail);
2563 
2564 	return gFail;
2565 }
2566