xmltest.cpp 30 KB

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