xmltest.cpp 31 KB

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