xmltest.cpp 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051
  1. #if defined( _MSC_VER )
  2. #define _CRT_SECURE_NO_WARNINGS // This test file is not intended to be secure.
  3. #endif
  4. #include "tinyxml2.h"
  5. #include <cstdlib>
  6. #include <cstring>
  7. #include <ctime>
  8. #if defined( _MSC_VER )
  9. #include <direct.h> // _mkdir
  10. #include <crtdbg.h>
  11. #define WIN32_LEAN_AND_MEAN
  12. #include <windows.h>
  13. _CrtMemState startMemState;
  14. _CrtMemState endMemState;
  15. #else
  16. #include <sys/stat.h> // mkdir
  17. #endif
  18. using namespace tinyxml2;
  19. int gPass = 0;
  20. int gFail = 0;
  21. bool XMLTest (const char* testString, const char* expected, const char* found, bool echo=true )
  22. {
  23. bool pass = !strcmp( expected, found );
  24. if ( pass )
  25. printf ("[pass]");
  26. else
  27. printf ("[fail]");
  28. if ( !echo )
  29. printf (" %s\n", testString);
  30. else
  31. printf (" %s [%s][%s]\n", testString, expected, found);
  32. if ( pass )
  33. ++gPass;
  34. else
  35. ++gFail;
  36. return pass;
  37. }
  38. template< class T > bool XMLTest( const char* testString, T expected, T found, bool echo=true )
  39. {
  40. bool pass = ( expected == found );
  41. if ( pass )
  42. printf ("[pass]");
  43. else
  44. printf ("[fail]");
  45. if ( !echo )
  46. printf (" %s\n", testString);
  47. else
  48. printf (" %s [%d][%d]\n", testString, static_cast<int>(expected), static_cast<int>(found) );
  49. if ( pass )
  50. ++gPass;
  51. else
  52. ++gFail;
  53. return pass;
  54. }
  55. void NullLineEndings( char* p )
  56. {
  57. while( p && *p ) {
  58. if ( *p == '\n' || *p == '\r' ) {
  59. *p = 0;
  60. return;
  61. }
  62. ++p;
  63. }
  64. }
  65. // Comments in the header. (Don't know how to get Doxygen to read comments in this file.)
  66. int example_1()
  67. {
  68. XMLDocument doc;
  69. doc.LoadFile( "resources/dream.xml" );
  70. return doc.ErrorID();
  71. }
  72. // Comments in the header. (Don't know how to get Doxygen to read comments in this file.)
  73. int example_2()
  74. {
  75. static const char* xml = "<element/>";
  76. XMLDocument doc;
  77. doc.Parse( xml );
  78. return doc.ErrorID();
  79. }
  80. int example_3()
  81. {
  82. static const char* xml =
  83. "<?xml version=\"1.0\"?>"
  84. "<!DOCTYPE PLAY SYSTEM \"play.dtd\">"
  85. "<PLAY>"
  86. "<TITLE>A Midsummer Night's Dream</TITLE>"
  87. "</PLAY>";
  88. XMLDocument doc;
  89. doc.Parse( xml );
  90. XMLElement* titleElement = doc.FirstChildElement( "PLAY" )->FirstChildElement( "TITLE" );
  91. const char* title = titleElement->GetText();
  92. printf( "Name of play (1): %s\n", title );
  93. XMLText* textNode = titleElement->FirstChild()->ToText();
  94. title = textNode->Value();
  95. printf( "Name of play (2): %s\n", title );
  96. return doc.ErrorID();
  97. }
  98. bool example_4()
  99. {
  100. static const char* xml =
  101. "<information>"
  102. " <attributeApproach v='2' />"
  103. " <textApproach>"
  104. " <v>2</v>"
  105. " </textApproach>"
  106. "</information>";
  107. XMLDocument doc;
  108. doc.Parse( xml );
  109. int v0 = 0;
  110. int v1 = 0;
  111. XMLElement* attributeApproachElement = doc.FirstChildElement()->FirstChildElement( "attributeApproach" );
  112. attributeApproachElement->QueryIntAttribute( "v", &v0 );
  113. XMLElement* textApproachElement = doc.FirstChildElement()->FirstChildElement( "textApproach" );
  114. textApproachElement->FirstChildElement( "v" )->QueryIntText( &v1 );
  115. printf( "Both values are the same: %d and %d\n", v0, v1 );
  116. return !doc.Error() && ( v0 == v1 );
  117. }
  118. int main( int /*argc*/, const char ** /*argv*/ )
  119. {
  120. #if defined( _MSC_VER ) && defined( DEBUG )
  121. _CrtMemCheckpoint( &startMemState );
  122. #endif
  123. #if defined(_MSC_VER)
  124. _mkdir( "resources/out/" );
  125. #else
  126. mkdir( "resources/out/", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
  127. #endif
  128. FILE* fp = fopen( "resources/dream.xml", "r" );
  129. if ( !fp ) {
  130. printf( "Error opening test file 'dream.xml'.\n"
  131. "Is your working directory the same as where \n"
  132. "the xmltest.cpp and dream.xml file are?\n\n"
  133. #if defined( _MSC_VER )
  134. "In windows Visual Studio you may need to set\n"
  135. "Properties->Debugging->Working Directory to '..'\n"
  136. #endif
  137. );
  138. exit( 1 );
  139. }
  140. fclose( fp );
  141. XMLTest( "Example-1", 0, example_1() );
  142. XMLTest( "Example-2", 0, example_2() );
  143. XMLTest( "Example-3", 0, example_3() );
  144. XMLTest( "Example-4", true, example_4() );
  145. /* ------ Example 2: Lookup information. ---- */
  146. {
  147. static const char* test[] = { "<element />",
  148. "<element></element>",
  149. "<element><subelement/></element>",
  150. "<element><subelement></subelement></element>",
  151. "<element><subelement><subsub/></subelement></element>",
  152. "<!--comment beside elements--><element><subelement></subelement></element>",
  153. "<!--comment beside elements, this time with spaces--> \n <element> <subelement> \n </subelement> </element>",
  154. "<element attrib1='foo' attrib2=\"bar\" ></element>",
  155. "<element attrib1='foo' attrib2=\"bar\" ><subelement attrib3='yeehaa' /></element>",
  156. "<element>Text inside element.</element>",
  157. "<element><b></b></element>",
  158. "<element>Text inside and <b>bolded</b> in the element.</element>",
  159. "<outer><element>Text inside and <b>bolded</b> in the element.</element></outer>",
  160. "<element>This &amp; That.</element>",
  161. "<element attrib='This&lt;That' />",
  162. 0
  163. };
  164. for( int i=0; test[i]; ++i ) {
  165. XMLDocument doc;
  166. doc.Parse( test[i] );
  167. doc.Print();
  168. printf( "----------------------------------------------\n" );
  169. }
  170. }
  171. #if 1
  172. {
  173. static const char* test = "<!--hello world\n"
  174. " line 2\r"
  175. " line 3\r\n"
  176. " line 4\n\r"
  177. " line 5\r-->";
  178. XMLDocument doc;
  179. doc.Parse( test );
  180. doc.Print();
  181. }
  182. {
  183. static const char* test = "<element>Text before.</element>";
  184. XMLDocument doc;
  185. doc.Parse( test );
  186. XMLElement* root = doc.FirstChildElement();
  187. XMLElement* newElement = doc.NewElement( "Subelement" );
  188. root->InsertEndChild( newElement );
  189. doc.Print();
  190. }
  191. {
  192. XMLDocument* doc = new XMLDocument();
  193. static const char* test = "<element><sub/></element>";
  194. doc->Parse( test );
  195. delete doc;
  196. }
  197. {
  198. // Test: Programmatic DOM
  199. // Build:
  200. // <element>
  201. // <!--comment-->
  202. // <sub attrib="1" />
  203. // <sub attrib="2" />
  204. // <sub attrib="3" >& Text!</sub>
  205. // <element>
  206. XMLDocument* doc = new XMLDocument();
  207. XMLNode* element = doc->InsertEndChild( doc->NewElement( "element" ) );
  208. XMLElement* sub[3] = { doc->NewElement( "sub" ), doc->NewElement( "sub" ), doc->NewElement( "sub" ) };
  209. for( int i=0; i<3; ++i ) {
  210. sub[i]->SetAttribute( "attrib", i );
  211. }
  212. element->InsertEndChild( sub[2] );
  213. XMLNode* comment = element->InsertFirstChild( doc->NewComment( "comment" ) );
  214. element->InsertAfterChild( comment, sub[0] );
  215. element->InsertAfterChild( sub[0], sub[1] );
  216. sub[2]->InsertFirstChild( doc->NewText( "& Text!" ));
  217. doc->Print();
  218. XMLTest( "Programmatic DOM", "comment", doc->FirstChildElement( "element" )->FirstChild()->Value() );
  219. XMLTest( "Programmatic DOM", "0", doc->FirstChildElement( "element" )->FirstChildElement()->Attribute( "attrib" ) );
  220. XMLTest( "Programmatic DOM", 2, doc->FirstChildElement()->LastChildElement( "sub" )->IntAttribute( "attrib" ) );
  221. XMLTest( "Programmatic DOM", "& Text!",
  222. doc->FirstChildElement()->LastChildElement( "sub" )->FirstChild()->ToText()->Value() );
  223. // And now deletion:
  224. element->DeleteChild( sub[2] );
  225. doc->DeleteNode( comment );
  226. element->FirstChildElement()->SetAttribute( "attrib", true );
  227. element->LastChildElement()->DeleteAttribute( "attrib" );
  228. XMLTest( "Programmatic DOM", true, doc->FirstChildElement()->FirstChildElement()->BoolAttribute( "attrib" ) );
  229. int value = 10;
  230. int result = doc->FirstChildElement()->LastChildElement()->QueryIntAttribute( "attrib", &value );
  231. XMLTest( "Programmatic DOM", result, (int)XML_NO_ATTRIBUTE );
  232. XMLTest( "Programmatic DOM", value, 10 );
  233. doc->Print();
  234. {
  235. XMLPrinter streamer;
  236. doc->Print( &streamer );
  237. printf( "%s", streamer.CStr() );
  238. }
  239. {
  240. XMLPrinter streamer( 0, true );
  241. doc->Print( &streamer );
  242. XMLTest( "Compact mode", "<element><sub attrib=\"1\"/><sub/></element>", streamer.CStr(), false );
  243. }
  244. doc->SaveFile( "./resources/out/pretty.xml" );
  245. doc->SaveFile( "./resources/out/compact.xml", true );
  246. delete doc;
  247. }
  248. {
  249. // Test: Dream
  250. // XML1 : 1,187,569 bytes in 31,209 allocations
  251. // XML2 : 469,073 bytes in 323 allocations
  252. //int newStart = gNew;
  253. XMLDocument doc;
  254. doc.LoadFile( "resources/dream.xml" );
  255. doc.SaveFile( "resources/out/dreamout.xml" );
  256. doc.PrintError();
  257. XMLTest( "Dream", "xml version=\"1.0\"",
  258. doc.FirstChild()->ToDeclaration()->Value() );
  259. XMLTest( "Dream", true, doc.FirstChild()->NextSibling()->ToUnknown() ? true : false );
  260. XMLTest( "Dream", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
  261. doc.FirstChild()->NextSibling()->ToUnknown()->Value() );
  262. XMLTest( "Dream", "And Robin shall restore amends.",
  263. doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
  264. XMLTest( "Dream", "And Robin shall restore amends.",
  265. doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
  266. XMLDocument doc2;
  267. doc2.LoadFile( "resources/out/dreamout.xml" );
  268. XMLTest( "Dream-out", "xml version=\"1.0\"",
  269. doc2.FirstChild()->ToDeclaration()->Value() );
  270. XMLTest( "Dream-out", true, doc2.FirstChild()->NextSibling()->ToUnknown() ? true : false );
  271. XMLTest( "Dream-out", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
  272. doc2.FirstChild()->NextSibling()->ToUnknown()->Value() );
  273. XMLTest( "Dream-out", "And Robin shall restore amends.",
  274. doc2.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
  275. //gNewTotal = gNew - newStart;
  276. }
  277. {
  278. const char* error = "<?xml version=\"1.0\" standalone=\"no\" ?>\n"
  279. "<passages count=\"006\" formatversion=\"20020620\">\n"
  280. " <wrong error>\n"
  281. "</passages>";
  282. XMLDocument doc;
  283. doc.Parse( error );
  284. XMLTest( "Bad XML", doc.ErrorID(), XML_ERROR_PARSING_ATTRIBUTE );
  285. }
  286. {
  287. const char* str = "<doc attr0='1' attr1='2.0' attr2='foo' />";
  288. XMLDocument doc;
  289. doc.Parse( str );
  290. XMLElement* ele = doc.FirstChildElement();
  291. int iVal, result;
  292. double dVal;
  293. result = ele->QueryDoubleAttribute( "attr0", &dVal );
  294. XMLTest( "Query attribute: int as double", result, (int)XML_NO_ERROR );
  295. XMLTest( "Query attribute: int as double", (int)dVal, 1 );
  296. result = ele->QueryDoubleAttribute( "attr1", &dVal );
  297. XMLTest( "Query attribute: double as double", (int)dVal, 2 );
  298. result = ele->QueryIntAttribute( "attr1", &iVal );
  299. XMLTest( "Query attribute: double as int", result, (int)XML_NO_ERROR );
  300. XMLTest( "Query attribute: double as int", iVal, 2 );
  301. result = ele->QueryIntAttribute( "attr2", &iVal );
  302. XMLTest( "Query attribute: not a number", result, (int)XML_WRONG_ATTRIBUTE_TYPE );
  303. result = ele->QueryIntAttribute( "bar", &iVal );
  304. XMLTest( "Query attribute: does not exist", result, (int)XML_NO_ATTRIBUTE );
  305. }
  306. {
  307. const char* str = "<doc/>";
  308. XMLDocument doc;
  309. doc.Parse( str );
  310. XMLElement* ele = doc.FirstChildElement();
  311. int iVal;
  312. double dVal;
  313. ele->SetAttribute( "str", "strValue" );
  314. ele->SetAttribute( "int", 1 );
  315. ele->SetAttribute( "double", -1.0 );
  316. const char* cStr = ele->Attribute( "str" );
  317. ele->QueryIntAttribute( "int", &iVal );
  318. ele->QueryDoubleAttribute( "double", &dVal );
  319. XMLTest( "Attribute match test", ele->Attribute( "str", "strValue" ), "strValue" );
  320. XMLTest( "Attribute round trip. c-string.", "strValue", cStr );
  321. XMLTest( "Attribute round trip. int.", 1, iVal );
  322. XMLTest( "Attribute round trip. double.", -1, (int)dVal );
  323. }
  324. {
  325. XMLDocument doc;
  326. doc.LoadFile( "resources/utf8test.xml" );
  327. // Get the attribute "value" from the "Russian" element and check it.
  328. XMLElement* element = doc.FirstChildElement( "document" )->FirstChildElement( "Russian" );
  329. const unsigned char correctValue[] = { 0xd1U, 0x86U, 0xd0U, 0xb5U, 0xd0U, 0xbdU, 0xd0U, 0xbdU,
  330. 0xd0U, 0xbeU, 0xd1U, 0x81U, 0xd1U, 0x82U, 0xd1U, 0x8cU, 0 };
  331. XMLTest( "UTF-8: Russian value.", (const char*)correctValue, element->Attribute( "value" ) );
  332. const unsigned char russianElementName[] = { 0xd0U, 0xa0U, 0xd1U, 0x83U,
  333. 0xd1U, 0x81U, 0xd1U, 0x81U,
  334. 0xd0U, 0xbaU, 0xd0U, 0xb8U,
  335. 0xd0U, 0xb9U, 0 };
  336. const char russianText[] = "<\xD0\xB8\xD0\xBC\xD0\xB5\xD0\xB5\xD1\x82>";
  337. XMLText* text = doc.FirstChildElement( "document" )->FirstChildElement( (const char*) russianElementName )->FirstChild()->ToText();
  338. XMLTest( "UTF-8: Browsing russian element name.",
  339. russianText,
  340. text->Value() );
  341. // Now try for a round trip.
  342. doc.SaveFile( "resources/out/utf8testout.xml" );
  343. // Check the round trip.
  344. int okay = 0;
  345. FILE* saved = fopen( "resources/out/utf8testout.xml", "r" );
  346. FILE* verify = fopen( "resources/utf8testverify.xml", "r" );
  347. if ( saved && verify )
  348. {
  349. okay = 1;
  350. char verifyBuf[256];
  351. while ( fgets( verifyBuf, 256, verify ) )
  352. {
  353. char savedBuf[256];
  354. fgets( savedBuf, 256, saved );
  355. NullLineEndings( verifyBuf );
  356. NullLineEndings( savedBuf );
  357. if ( strcmp( verifyBuf, savedBuf ) )
  358. {
  359. printf( "verify:%s<\n", verifyBuf );
  360. printf( "saved :%s<\n", savedBuf );
  361. okay = 0;
  362. break;
  363. }
  364. }
  365. }
  366. if ( saved )
  367. fclose( saved );
  368. if ( verify )
  369. fclose( verify );
  370. XMLTest( "UTF-8: Verified multi-language round trip.", 1, okay );
  371. }
  372. // --------GetText()-----------
  373. {
  374. const char* str = "<foo>This is text</foo>";
  375. XMLDocument doc;
  376. doc.Parse( str );
  377. const XMLElement* element = doc.RootElement();
  378. XMLTest( "GetText() normal use.", "This is text", element->GetText() );
  379. str = "<foo><b>This is text</b></foo>";
  380. doc.Parse( str );
  381. element = doc.RootElement();
  382. XMLTest( "GetText() contained element.", element->GetText() == 0, true );
  383. }
  384. // ---------- CDATA ---------------
  385. {
  386. const char* str = "<xmlElement>"
  387. "<![CDATA["
  388. "I am > the rules!\n"
  389. "...since I make symbolic puns"
  390. "]]>"
  391. "</xmlElement>";
  392. XMLDocument doc;
  393. doc.Parse( str );
  394. doc.Print();
  395. XMLTest( "CDATA parse.", doc.FirstChildElement()->FirstChild()->Value(),
  396. "I am > the rules!\n...since I make symbolic puns",
  397. false );
  398. }
  399. // ----------- CDATA -------------
  400. {
  401. const char* str = "<xmlElement>"
  402. "<![CDATA["
  403. "<b>I am > the rules!</b>\n"
  404. "...since I make symbolic puns"
  405. "]]>"
  406. "</xmlElement>";
  407. XMLDocument doc;
  408. doc.Parse( str );
  409. doc.Print();
  410. XMLTest( "CDATA parse. [ tixml1:1480107 ]", doc.FirstChildElement()->FirstChild()->Value(),
  411. "<b>I am > the rules!</b>\n...since I make symbolic puns",
  412. false );
  413. }
  414. // InsertAfterChild causes crash.
  415. {
  416. // InsertBeforeChild and InsertAfterChild causes crash.
  417. XMLDocument doc;
  418. XMLElement* parent = doc.NewElement( "Parent" );
  419. doc.InsertFirstChild( parent );
  420. XMLElement* childText0 = doc.NewElement( "childText0" );
  421. XMLElement* childText1 = doc.NewElement( "childText1" );
  422. XMLNode* childNode0 = parent->InsertEndChild( childText0 );
  423. XMLNode* childNode1 = parent->InsertAfterChild( childNode0, childText1 );
  424. XMLTest( "Test InsertAfterChild on empty node. ", ( childNode1 == parent->LastChild() ), true );
  425. }
  426. {
  427. // Entities not being written correctly.
  428. // From Lynn Allen
  429. const char* passages =
  430. "<?xml version=\"1.0\" standalone=\"no\" ?>"
  431. "<passages count=\"006\" formatversion=\"20020620\">"
  432. "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
  433. " It also has &lt;, &gt;, and &amp;, as well as a fake copyright &#xA9;.\"> </psg>"
  434. "</passages>";
  435. XMLDocument doc;
  436. doc.Parse( passages );
  437. XMLElement* psg = doc.RootElement()->FirstChildElement();
  438. const char* context = psg->Attribute( "context" );
  439. const char* expected = "Line 5 has \"quotation marks\" and 'apostrophe marks'. It also has <, >, and &, as well as a fake copyright \xC2\xA9.";
  440. XMLTest( "Entity transformation: read. ", expected, context, true );
  441. FILE* textfile = fopen( "resources/out/textfile.txt", "w" );
  442. if ( textfile )
  443. {
  444. XMLPrinter streamer( textfile );
  445. psg->Accept( &streamer );
  446. fclose( textfile );
  447. }
  448. textfile = fopen( "resources/out/textfile.txt", "r" );
  449. TIXMLASSERT( textfile );
  450. if ( textfile )
  451. {
  452. char buf[ 1024 ];
  453. fgets( buf, 1024, textfile );
  454. XMLTest( "Entity transformation: write. ",
  455. "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
  456. " It also has &lt;, &gt;, and &amp;, as well as a fake copyright \xC2\xA9.\"/>\n",
  457. buf, false );
  458. fclose( textfile );
  459. }
  460. }
  461. {
  462. // Suppress entities.
  463. const char* passages =
  464. "<?xml version=\"1.0\" standalone=\"no\" ?>"
  465. "<passages count=\"006\" formatversion=\"20020620\">"
  466. "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.\">Crazy &ttk;</psg>"
  467. "</passages>";
  468. XMLDocument doc( false );
  469. doc.Parse( passages );
  470. XMLTest( "No entity parsing.", doc.FirstChildElement()->FirstChildElement()->Attribute( "context" ),
  471. "Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;." );
  472. XMLTest( "No entity parsing.", doc.FirstChildElement()->FirstChildElement()->FirstChild()->Value(),
  473. "Crazy &ttk;" );
  474. doc.Print();
  475. }
  476. {
  477. const char* test = "<?xml version='1.0'?><a.elem xmi.version='2.0'/>";
  478. XMLDocument doc;
  479. doc.Parse( test );
  480. XMLTest( "dot in names", doc.Error(), false );
  481. XMLTest( "dot in names", doc.FirstChildElement()->Name(), "a.elem" );
  482. XMLTest( "dot in names", doc.FirstChildElement()->Attribute( "xmi.version" ), "2.0" );
  483. }
  484. {
  485. const char* test = "<element><Name>1.1 Start easy ignore fin thickness&#xA;</Name></element>";
  486. XMLDocument doc;
  487. doc.Parse( test );
  488. XMLText* text = doc.FirstChildElement()->FirstChildElement()->FirstChild()->ToText();
  489. XMLTest( "Entity with one digit.",
  490. text->Value(), "1.1 Start easy ignore fin thickness\n",
  491. false );
  492. }
  493. {
  494. // DOCTYPE not preserved (950171)
  495. //
  496. const char* doctype =
  497. "<?xml version=\"1.0\" ?>"
  498. "<!DOCTYPE PLAY SYSTEM 'play.dtd'>"
  499. "<!ELEMENT title (#PCDATA)>"
  500. "<!ELEMENT books (title,authors)>"
  501. "<element />";
  502. XMLDocument doc;
  503. doc.Parse( doctype );
  504. doc.SaveFile( "resources/out/test7.xml" );
  505. doc.DeleteChild( doc.RootElement() );
  506. doc.LoadFile( "resources/out/test7.xml" );
  507. doc.Print();
  508. const XMLUnknown* decl = doc.FirstChild()->NextSibling()->ToUnknown();
  509. XMLTest( "Correct value of unknown.", "DOCTYPE PLAY SYSTEM 'play.dtd'", decl->Value() );
  510. }
  511. {
  512. // Comments do not stream out correctly.
  513. const char* doctype =
  514. "<!-- Somewhat<evil> -->";
  515. XMLDocument doc;
  516. doc.Parse( doctype );
  517. XMLComment* comment = doc.FirstChild()->ToComment();
  518. XMLTest( "Comment formatting.", " Somewhat<evil> ", comment->Value() );
  519. }
  520. {
  521. // Double attributes
  522. const char* doctype = "<element attr='red' attr='blue' />";
  523. XMLDocument doc;
  524. doc.Parse( doctype );
  525. XMLTest( "Parsing repeated attributes.", XML_ERROR_PARSING_ATTRIBUTE, doc.ErrorID() ); // is an error to tinyxml (didn't use to be, but caused issues)
  526. doc.PrintError();
  527. }
  528. {
  529. // Embedded null in stream.
  530. const char* doctype = "<element att\0r='red' attr='blue' />";
  531. XMLDocument doc;
  532. doc.Parse( doctype );
  533. XMLTest( "Embedded null throws error.", true, doc.Error() );
  534. }
  535. {
  536. // Empty documents should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
  537. const char* str = " ";
  538. XMLDocument doc;
  539. doc.Parse( str );
  540. XMLTest( "Empty document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
  541. }
  542. {
  543. // Low entities
  544. XMLDocument doc;
  545. doc.Parse( "<test>&#x0e;</test>" );
  546. const char result[] = { 0x0e, 0 };
  547. XMLTest( "Low entities.", doc.FirstChildElement()->GetText(), result );
  548. doc.Print();
  549. }
  550. {
  551. // Attribute values with trailing quotes not handled correctly
  552. XMLDocument doc;
  553. doc.Parse( "<foo attribute=bar\" />" );
  554. XMLTest( "Throw error with bad end quotes.", doc.Error(), true );
  555. }
  556. {
  557. // [ 1663758 ] Failure to report error on bad XML
  558. XMLDocument xml;
  559. xml.Parse("<x>");
  560. XMLTest("Missing end tag at end of input", xml.Error(), true);
  561. xml.Parse("<x> ");
  562. XMLTest("Missing end tag with trailing whitespace", xml.Error(), true);
  563. xml.Parse("<x></y>");
  564. XMLTest("Mismatched tags", xml.ErrorID(), XML_ERROR_MISMATCHED_ELEMENT);
  565. }
  566. {
  567. // [ 1475201 ] TinyXML parses entities in comments
  568. XMLDocument xml;
  569. xml.Parse("<!-- declarations for <head> & <body> -->"
  570. "<!-- far &amp; away -->" );
  571. XMLNode* e0 = xml.FirstChild();
  572. XMLNode* e1 = e0->NextSibling();
  573. XMLComment* c0 = e0->ToComment();
  574. XMLComment* c1 = e1->ToComment();
  575. XMLTest( "Comments ignore entities.", " declarations for <head> & <body> ", c0->Value(), true );
  576. XMLTest( "Comments ignore entities.", " far &amp; away ", c1->Value(), true );
  577. }
  578. {
  579. XMLDocument xml;
  580. xml.Parse( "<Parent>"
  581. "<child1 att=''/>"
  582. "<!-- With this comment, child2 will not be parsed! -->"
  583. "<child2 att=''/>"
  584. "</Parent>" );
  585. xml.Print();
  586. int count = 0;
  587. for( XMLNode* ele = xml.FirstChildElement( "Parent" )->FirstChild();
  588. ele;
  589. ele = ele->NextSibling() )
  590. {
  591. ++count;
  592. }
  593. XMLTest( "Comments iterate correctly.", 3, count );
  594. }
  595. {
  596. // trying to repro ]1874301]. If it doesn't go into an infinite loop, all is well.
  597. unsigned char buf[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?><feed><![CDATA[Test XMLblablablalblbl";
  598. buf[60] = 239;
  599. buf[61] = 0;
  600. XMLDocument doc;
  601. doc.Parse( (const char*)buf);
  602. }
  603. {
  604. // bug 1827248 Error while parsing a little bit malformed file
  605. // Actually not malformed - should work.
  606. XMLDocument xml;
  607. xml.Parse( "<attributelist> </attributelist >" );
  608. XMLTest( "Handle end tag whitespace", false, xml.Error() );
  609. }
  610. {
  611. // This one must not result in an infinite loop
  612. XMLDocument xml;
  613. xml.Parse( "<infinite>loop" );
  614. XMLTest( "Infinite loop test.", true, true );
  615. }
  616. #endif
  617. {
  618. const char* pub = "<?xml version='1.0'?> <element><sub/></element> <!--comment--> <!DOCTYPE>";
  619. XMLDocument doc;
  620. doc.Parse( pub );
  621. XMLDocument clone;
  622. for( const XMLNode* node=doc.FirstChild(); node; node=node->NextSibling() ) {
  623. XMLNode* copy = node->ShallowClone( &clone );
  624. clone.InsertEndChild( copy );
  625. }
  626. clone.Print();
  627. int count=0;
  628. const XMLNode* a=clone.FirstChild();
  629. const XMLNode* b=doc.FirstChild();
  630. for( ; a && b; a=a->NextSibling(), b=b->NextSibling() ) {
  631. ++count;
  632. XMLTest( "Clone and Equal", true, a->ShallowEqual( b ));
  633. }
  634. XMLTest( "Clone and Equal", 4, count );
  635. }
  636. {
  637. // This shouldn't crash.
  638. XMLDocument doc;
  639. if(XML_NO_ERROR != doc.LoadFile( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ))
  640. {
  641. doc.PrintError();
  642. }
  643. XMLTest( "Error in snprinf handling.", true, doc.Error() );
  644. }
  645. {
  646. // Attribute ordering.
  647. static const char* xml = "<element attrib1=\"1\" attrib2=\"2\" attrib3=\"3\" />";
  648. XMLDocument doc;
  649. doc.Parse( xml );
  650. XMLElement* ele = doc.FirstChildElement();
  651. const XMLAttribute* a = ele->FirstAttribute();
  652. XMLTest( "Attribute order", "1", a->Value() );
  653. a = a->Next();
  654. XMLTest( "Attribute order", "2", a->Value() );
  655. a = a->Next();
  656. XMLTest( "Attribute order", "3", a->Value() );
  657. XMLTest( "Attribute order", "attrib3", a->Name() );
  658. ele->DeleteAttribute( "attrib2" );
  659. a = ele->FirstAttribute();
  660. XMLTest( "Attribute order", "1", a->Value() );
  661. a = a->Next();
  662. XMLTest( "Attribute order", "3", a->Value() );
  663. ele->DeleteAttribute( "attrib1" );
  664. ele->DeleteAttribute( "attrib3" );
  665. XMLTest( "Attribute order (empty)", false, ele->FirstAttribute() ? true : false );
  666. }
  667. {
  668. // Make sure an attribute with a space in it succeeds.
  669. static const char* xml0 = "<element attribute1= \"Test Attribute\"/>";
  670. static const char* xml1 = "<element attribute1 =\"Test Attribute\"/>";
  671. static const char* xml2 = "<element attribute1 = \"Test Attribute\"/>";
  672. XMLDocument doc0;
  673. doc0.Parse( xml0 );
  674. XMLDocument doc1;
  675. doc1.Parse( xml1 );
  676. XMLDocument doc2;
  677. doc2.Parse( xml2 );
  678. XMLElement* ele = 0;
  679. ele = doc0.FirstChildElement();
  680. XMLTest( "Attribute with space #1", "Test Attribute", ele->Attribute( "attribute1" ) );
  681. ele = doc1.FirstChildElement();
  682. XMLTest( "Attribute with space #2", "Test Attribute", ele->Attribute( "attribute1" ) );
  683. ele = doc2.FirstChildElement();
  684. XMLTest( "Attribute with space #3", "Test Attribute", ele->Attribute( "attribute1" ) );
  685. }
  686. {
  687. // Make sure we don't go into an infinite loop.
  688. static const char* xml = "<doc><element attribute='attribute'/><element attribute='attribute'/></doc>";
  689. XMLDocument doc;
  690. doc.Parse( xml );
  691. XMLElement* ele0 = doc.FirstChildElement()->FirstChildElement();
  692. XMLElement* ele1 = ele0->NextSiblingElement();
  693. bool equal = ele0->ShallowEqual( ele1 );
  694. XMLTest( "Infinite loop in shallow equal.", true, equal );
  695. }
  696. // -------- Handles ------------
  697. {
  698. static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
  699. XMLDocument doc;
  700. doc.Parse( xml );
  701. XMLElement* ele = XMLHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
  702. XMLTest( "Handle, success, mutable", ele->Value(), "sub" );
  703. XMLHandle docH( doc );
  704. ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
  705. XMLTest( "Handle, dne, mutable", false, ele != 0 );
  706. }
  707. {
  708. static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
  709. XMLDocument doc;
  710. doc.Parse( xml );
  711. XMLConstHandle docH( doc );
  712. const XMLElement* ele = docH.FirstChildElement( "element" ).FirstChild().ToElement();
  713. XMLTest( "Handle, success, const", ele->Value(), "sub" );
  714. ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
  715. XMLTest( "Handle, dne, const", false, ele != 0 );
  716. }
  717. {
  718. // Default Declaration & BOM
  719. XMLDocument doc;
  720. doc.InsertEndChild( doc.NewDeclaration() );
  721. doc.SetBOM( true );
  722. XMLPrinter printer;
  723. doc.Print( &printer );
  724. static const char* result = "\xef\xbb\xbf<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
  725. XMLTest( "BOM and default declaration", printer.CStr(), result, false );
  726. XMLTest( "CStrSize", printer.CStrSize(), 42, false );
  727. }
  728. {
  729. const char* xml = "<ipxml ws='1'><info bla=' /></ipxml>";
  730. XMLDocument doc;
  731. doc.Parse( xml );
  732. XMLTest( "Ill formed XML", true, doc.Error() );
  733. }
  734. // QueryXYZText
  735. {
  736. const char* xml = "<point> <x>1.2</x> <y>1</y> <z>38</z> <valid>true</valid> </point>";
  737. XMLDocument doc;
  738. doc.Parse( xml );
  739. const XMLElement* pointElement = doc.RootElement();
  740. int intValue = 0;
  741. unsigned unsignedValue = 0;
  742. float floatValue = 0;
  743. double doubleValue = 0;
  744. bool boolValue = false;
  745. pointElement->FirstChildElement( "y" )->QueryIntText( &intValue );
  746. pointElement->FirstChildElement( "y" )->QueryUnsignedText( &unsignedValue );
  747. pointElement->FirstChildElement( "x" )->QueryFloatText( &floatValue );
  748. pointElement->FirstChildElement( "x" )->QueryDoubleText( &doubleValue );
  749. pointElement->FirstChildElement( "valid" )->QueryBoolText( &boolValue );
  750. XMLTest( "QueryIntText", intValue, 1, false );
  751. XMLTest( "QueryUnsignedText", unsignedValue, (unsigned)1, false );
  752. XMLTest( "QueryFloatText", floatValue, 1.2f, false );
  753. XMLTest( "QueryDoubleText", doubleValue, 1.2, false );
  754. XMLTest( "QueryBoolText", boolValue, true, false );
  755. }
  756. {
  757. const char* xml = "<element><_sub/><:sub/><sub:sub/><sub-sub/></element>";
  758. XMLDocument doc;
  759. doc.Parse( xml );
  760. XMLTest( "Non-alpha element lead letter parses.", doc.Error(), false );
  761. }
  762. {
  763. const char* xml = "<element/>WOA THIS ISN'T GOING TO PARSE";
  764. XMLDocument doc;
  765. doc.Parse( xml, 10 );
  766. XMLTest( "Set length of incoming data", doc.Error(), false );
  767. }
  768. // ----------- Whitespace ------------
  769. {
  770. const char* xml = "<element>"
  771. "<a> This \nis &apos; text &apos; </a>"
  772. "<b> This is &apos; text &apos; \n</b>"
  773. "<c>This is &apos; \n\n text &apos;</c>"
  774. "</element>";
  775. XMLDocument doc( true, COLLAPSE_WHITESPACE );
  776. doc.Parse( xml );
  777. const XMLElement* element = doc.FirstChildElement();
  778. for( const XMLElement* parent = element->FirstChildElement();
  779. parent;
  780. parent = parent->NextSiblingElement() )
  781. {
  782. XMLTest( "Whitespace collapse", "This is ' text '", parent->GetText() );
  783. }
  784. }
  785. #if 0
  786. {
  787. // Passes if assert doesn't fire.
  788. XMLDocument xmlDoc;
  789. xmlDoc.NewDeclaration();
  790. xmlDoc.NewComment("Configuration file");
  791. XMLElement *root = xmlDoc.NewElement("settings");
  792. root->SetAttribute("version", 2);
  793. }
  794. #endif
  795. {
  796. const char* xml = "<element> </element>";
  797. XMLDocument doc( true, COLLAPSE_WHITESPACE );
  798. doc.Parse( xml );
  799. XMLTest( "Whitespace all space", true, 0 == doc.FirstChildElement()->FirstChild() );
  800. }
  801. #if 0 // the question being explored is what kind of print to use:
  802. // https://github.com/leethomason/tinyxml2/issues/63
  803. {
  804. const char* xml = "<element attrA='123456789.123456789' attrB='1.001e9'/>";
  805. XMLDocument doc;
  806. doc.Parse( xml );
  807. doc.FirstChildElement()->SetAttribute( "attrA", 123456789.123456789 );
  808. doc.FirstChildElement()->SetAttribute( "attrB", 1.001e9 );
  809. doc.Print();
  810. }
  811. #endif
  812. {
  813. // An assert should not fire.
  814. const char* xml = "<element/>";
  815. XMLDocument doc;
  816. doc.Parse( xml );
  817. XMLElement* ele = doc.NewElement( "unused" ); // This will get cleaned up with the 'doc' going out of scope.
  818. XMLTest( "Tracking unused elements", true, ele != 0, false );
  819. }
  820. // ----------- Performance tracking --------------
  821. {
  822. #if defined( _MSC_VER )
  823. __int64 start, end, freq;
  824. QueryPerformanceFrequency( (LARGE_INTEGER*) &freq );
  825. #endif
  826. FILE* fp = fopen( "resources/dream.xml", "r" );
  827. fseek( fp, 0, SEEK_END );
  828. long size = ftell( fp );
  829. fseek( fp, 0, SEEK_SET );
  830. char* mem = new char[size+1];
  831. fread( mem, size, 1, fp );
  832. fclose( fp );
  833. mem[size] = 0;
  834. #if defined( _MSC_VER )
  835. QueryPerformanceCounter( (LARGE_INTEGER*) &start );
  836. #else
  837. clock_t cstart = clock();
  838. #endif
  839. static const int COUNT = 10;
  840. for( int i=0; i<COUNT; ++i ) {
  841. XMLDocument doc;
  842. doc.Parse( mem );
  843. }
  844. #if defined( _MSC_VER )
  845. QueryPerformanceCounter( (LARGE_INTEGER*) &end );
  846. #else
  847. clock_t cend = clock();
  848. #endif
  849. delete [] mem;
  850. static const char* note =
  851. #ifdef DEBUG
  852. "DEBUG";
  853. #else
  854. "Release";
  855. #endif
  856. #if defined( _MSC_VER )
  857. printf( "\nParsing %s of dream.xml: %.3f milli-seconds\n", note, 1000.0 * (double)(end-start) / ( (double)freq * (double)COUNT) );
  858. #else
  859. printf( "\nParsing %s of dream.xml: %.3f milli-seconds\n", note, (double)(cend - cstart)/(double)COUNT );
  860. #endif
  861. }
  862. #if defined( _MSC_VER ) && defined( DEBUG )
  863. _CrtMemCheckpoint( &endMemState );
  864. //_CrtMemDumpStatistics( &endMemState );
  865. _CrtMemState diffMemState;
  866. _CrtMemDifference( &diffMemState, &startMemState, &endMemState );
  867. _CrtMemDumpStatistics( &diffMemState );
  868. //printf( "new total=%d\n", gNewTotal );
  869. #endif
  870. printf ("\nPass %d, Fail %d\n", gPass, gFail);
  871. return 0;
  872. }