xmltest.cpp 31 KB

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