xmltest.cpp 30 KB

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