xmltest.cpp 63 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016
  1. #if defined( _MSC_VER )
  2. #if !defined( _CRT_SECURE_NO_WARNINGS )
  3. #define _CRT_SECURE_NO_WARNINGS // This test file is not intended to be secure.
  4. #endif
  5. #endif
  6. #include "tinyxml2.h"
  7. #include <cerrno>
  8. #include <cstdlib>
  9. #include <cstring>
  10. #include <ctime>
  11. #if defined( _MSC_VER ) || defined (WIN32)
  12. #include <crtdbg.h>
  13. #define WIN32_LEAN_AND_MEAN
  14. #include <windows.h>
  15. _CrtMemState startMemState;
  16. _CrtMemState endMemState;
  17. #else
  18. #include <sys/stat.h>
  19. #include <sys/types.h>
  20. #endif
  21. using namespace tinyxml2;
  22. using namespace std;
  23. int gPass = 0;
  24. int gFail = 0;
  25. bool XMLTest (const char* testString, const char* expected, const char* found, bool echo=true, bool extraNL=false )
  26. {
  27. bool pass;
  28. if ( !expected && !found )
  29. pass = true;
  30. else if ( !expected || !found )
  31. pass = false;
  32. else
  33. pass = !strcmp( expected, found );
  34. if ( pass )
  35. printf ("[pass]");
  36. else
  37. printf ("[fail]");
  38. if ( !echo ) {
  39. printf (" %s\n", testString);
  40. }
  41. else {
  42. if ( extraNL ) {
  43. printf( " %s\n", testString );
  44. printf( "%s\n", expected );
  45. printf( "%s\n", found );
  46. }
  47. else {
  48. printf (" %s [%s][%s]\n", testString, expected, found);
  49. }
  50. }
  51. if ( pass )
  52. ++gPass;
  53. else
  54. ++gFail;
  55. return pass;
  56. }
  57. bool XMLTest(const char* testString, XMLError expected, XMLError found, bool echo = true, bool extraNL = false)
  58. {
  59. return XMLTest(testString, XMLDocument::ErrorIDToName(expected), XMLDocument::ErrorIDToName(found), echo, extraNL);
  60. }
  61. bool XMLTest(const char* testString, bool expected, bool found, bool echo = true, bool extraNL = false)
  62. {
  63. return XMLTest(testString, expected ? "true" : "false", found ? "true" : "false", echo, extraNL);
  64. }
  65. template< class T > bool XMLTest( const char* testString, T expected, T found, bool echo=true )
  66. {
  67. bool pass = ( expected == found );
  68. if ( pass )
  69. printf ("[pass]");
  70. else
  71. printf ("[fail]");
  72. if ( !echo )
  73. printf (" %s\n", testString);
  74. else
  75. printf (" %s [%d][%d]\n", testString, static_cast<int>(expected), static_cast<int>(found) );
  76. if ( pass )
  77. ++gPass;
  78. else
  79. ++gFail;
  80. return pass;
  81. }
  82. void NullLineEndings( char* p )
  83. {
  84. while( p && *p ) {
  85. if ( *p == '\n' || *p == '\r' ) {
  86. *p = 0;
  87. return;
  88. }
  89. ++p;
  90. }
  91. }
  92. int example_1()
  93. {
  94. XMLDocument doc;
  95. doc.LoadFile( "resources/dream.xml" );
  96. return doc.ErrorID();
  97. }
  98. /** @page Example-1 Load an XML File
  99. * @dontinclude ./xmltest.cpp
  100. * Basic XML file loading.
  101. * The basic syntax to load an XML file from
  102. * disk and check for an error. (ErrorID()
  103. * will return 0 for no error.)
  104. * @skip example_1()
  105. * @until }
  106. */
  107. int example_2()
  108. {
  109. static const char* xml = "<element/>";
  110. XMLDocument doc;
  111. doc.Parse( xml );
  112. return doc.ErrorID();
  113. }
  114. /** @page Example-2 Parse an XML from char buffer
  115. * @dontinclude ./xmltest.cpp
  116. * Basic XML string parsing.
  117. * The basic syntax to parse an XML for
  118. * a char* and check for an error. (ErrorID()
  119. * will return 0 for no error.)
  120. * @skip example_2()
  121. * @until }
  122. */
  123. int example_3()
  124. {
  125. static const char* xml =
  126. "<?xml version=\"1.0\"?>"
  127. "<!DOCTYPE PLAY SYSTEM \"play.dtd\">"
  128. "<PLAY>"
  129. "<TITLE>A Midsummer Night's Dream</TITLE>"
  130. "</PLAY>";
  131. XMLDocument doc;
  132. doc.Parse( xml );
  133. XMLElement* titleElement = doc.FirstChildElement( "PLAY" )->FirstChildElement( "TITLE" );
  134. const char* title = titleElement->GetText();
  135. printf( "Name of play (1): %s\n", title );
  136. XMLText* textNode = titleElement->FirstChild()->ToText();
  137. title = textNode->Value();
  138. printf( "Name of play (2): %s\n", title );
  139. return doc.ErrorID();
  140. }
  141. /** @page Example-3 Get information out of XML
  142. @dontinclude ./xmltest.cpp
  143. In this example, we navigate a simple XML
  144. file, and read some interesting text. Note
  145. that this example doesn't use error
  146. checking; working code should check for null
  147. pointers when walking an XML tree, or use
  148. XMLHandle.
  149. (The XML is an excerpt from "dream.xml").
  150. @skip example_3()
  151. @until </PLAY>";
  152. The structure of the XML file is:
  153. <ul>
  154. <li>(declaration)</li>
  155. <li>(dtd stuff)</li>
  156. <li>Element "PLAY"</li>
  157. <ul>
  158. <li>Element "TITLE"</li>
  159. <ul>
  160. <li>Text "A Midsummer Night's Dream"</li>
  161. </ul>
  162. </ul>
  163. </ul>
  164. For this example, we want to print out the
  165. title of the play. The text of the title (what
  166. we want) is child of the "TITLE" element which
  167. is a child of the "PLAY" element.
  168. We want to skip the declaration and dtd, so the
  169. method FirstChildElement() is a good choice. The
  170. FirstChildElement() of the Document is the "PLAY"
  171. Element, the FirstChildElement() of the "PLAY" Element
  172. is the "TITLE" Element.
  173. @until ( "TITLE" );
  174. We can then use the convenience function GetText()
  175. to get the title of the play.
  176. @until title );
  177. Text is just another Node in the XML DOM. And in
  178. fact you should be a little cautious with it, as
  179. text nodes can contain elements.
  180. @verbatim
  181. Consider: A Midsummer Night's <b>Dream</b>
  182. @endverbatim
  183. It is more correct to actually query the Text Node
  184. if in doubt:
  185. @until title );
  186. Noting that here we use FirstChild() since we are
  187. looking for XMLText, not an element, and ToText()
  188. is a cast from a Node to a XMLText.
  189. */
  190. bool example_4()
  191. {
  192. static const char* xml =
  193. "<information>"
  194. " <attributeApproach v='2' />"
  195. " <textApproach>"
  196. " <v>2</v>"
  197. " </textApproach>"
  198. "</information>";
  199. XMLDocument doc;
  200. doc.Parse( xml );
  201. int v0 = 0;
  202. int v1 = 0;
  203. XMLElement* attributeApproachElement = doc.FirstChildElement()->FirstChildElement( "attributeApproach" );
  204. attributeApproachElement->QueryIntAttribute( "v", &v0 );
  205. XMLElement* textApproachElement = doc.FirstChildElement()->FirstChildElement( "textApproach" );
  206. textApproachElement->FirstChildElement( "v" )->QueryIntText( &v1 );
  207. printf( "Both values are the same: %d and %d\n", v0, v1 );
  208. return !doc.Error() && ( v0 == v1 );
  209. }
  210. /** @page Example-4 Read attributes and text information.
  211. @dontinclude ./xmltest.cpp
  212. There are fundamentally 2 ways of writing a key-value
  213. pair into an XML file. (Something that's always annoyed
  214. me about XML.) Either by using attributes, or by writing
  215. the key name into an element and the value into
  216. the text node wrapped by the element. Both approaches
  217. are illustrated in this example, which shows two ways
  218. to encode the value "2" into the key "v":
  219. @skip example_4()
  220. @until "</information>";
  221. TinyXML-2 has accessors for both approaches.
  222. When using an attribute, you navigate to the XMLElement
  223. with that attribute and use the QueryIntAttribute()
  224. group of methods. (Also QueryFloatAttribute(), etc.)
  225. @skip XMLElement* attributeApproachElement
  226. @until &v0 );
  227. When using the text approach, you need to navigate
  228. down one more step to the XMLElement that contains
  229. the text. Note the extra FirstChildElement( "v" )
  230. in the code below. The value of the text can then
  231. be safely queried with the QueryIntText() group
  232. of methods. (Also QueryFloatText(), etc.)
  233. @skip XMLElement* textApproachElement
  234. @until &v1 );
  235. */
  236. int main( int argc, const char ** argv )
  237. {
  238. #if defined( _MSC_VER ) && defined( DEBUG )
  239. _CrtMemCheckpoint( &startMemState );
  240. // Enable MS Visual C++ debug heap memory leaks dump on exit
  241. _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
  242. {
  243. int leaksOnStart = _CrtDumpMemoryLeaks();
  244. XMLTest( "No leaks on start?", FALSE, leaksOnStart );
  245. }
  246. #endif
  247. {
  248. TIXMLASSERT( true );
  249. }
  250. if ( argc > 1 ) {
  251. XMLDocument* doc = new XMLDocument();
  252. clock_t startTime = clock();
  253. doc->LoadFile( argv[1] );
  254. clock_t loadTime = clock();
  255. int errorID = doc->ErrorID();
  256. delete doc; doc = 0;
  257. clock_t deleteTime = clock();
  258. printf( "Test file '%s' loaded. ErrorID=%d\n", argv[1], errorID );
  259. if ( !errorID ) {
  260. printf( "Load time=%u\n", (unsigned)(loadTime - startTime) );
  261. printf( "Delete time=%u\n", (unsigned)(deleteTime - loadTime) );
  262. printf( "Total time=%u\n", (unsigned)(deleteTime - startTime) );
  263. }
  264. exit(0);
  265. }
  266. FILE* fp = fopen( "resources/dream.xml", "r" );
  267. if ( !fp ) {
  268. printf( "Error opening test file 'dream.xml'.\n"
  269. "Is your working directory the same as where \n"
  270. "the xmltest.cpp and dream.xml file are?\n\n"
  271. #if defined( _MSC_VER )
  272. "In windows Visual Studio you may need to set\n"
  273. "Properties->Debugging->Working Directory to '..'\n"
  274. #endif
  275. );
  276. exit( 1 );
  277. }
  278. fclose( fp );
  279. #if defined WIN32
  280. if ( !CreateDirectory( "resources/out", NULL ) && GetLastError() != ERROR_ALREADY_EXISTS ) {
  281. #else
  282. if ( mkdir( "resources/out", 0750 ) == -1 && errno != EEXIST ) {
  283. #endif
  284. printf( "Unable to create directory 'resources/out': %s\n", strerror( errno ) );
  285. exit( 1 );
  286. }
  287. XMLTest( "Example-1", 0, example_1() );
  288. XMLTest( "Example-2", 0, example_2() );
  289. XMLTest( "Example-3", 0, example_3() );
  290. XMLTest( "Example-4", true, example_4() );
  291. /* ------ Example 2: Lookup information. ---- */
  292. {
  293. static const char* test[] = { "<element />",
  294. "<element></element>",
  295. "<element><subelement/></element>",
  296. "<element><subelement></subelement></element>",
  297. "<element><subelement><subsub/></subelement></element>",
  298. "<!--comment beside elements--><element><subelement></subelement></element>",
  299. "<!--comment beside elements, this time with spaces--> \n <element> <subelement> \n </subelement> </element>",
  300. "<element attrib1='foo' attrib2=\"bar\" ></element>",
  301. "<element attrib1='foo' attrib2=\"bar\" ><subelement attrib3='yeehaa' /></element>",
  302. "<element>Text inside element.</element>",
  303. "<element><b></b></element>",
  304. "<element>Text inside and <b>bolded</b> in the element.</element>",
  305. "<outer><element>Text inside and <b>bolded</b> in the element.</element></outer>",
  306. "<element>This &amp; That.</element>",
  307. "<element attrib='This&lt;That' />",
  308. 0
  309. };
  310. for( int i=0; test[i]; ++i ) {
  311. XMLDocument doc;
  312. doc.Parse( test[i] );
  313. doc.Print();
  314. printf( "----------------------------------------------\n" );
  315. }
  316. }
  317. #if 1
  318. {
  319. static const char* test = "<!--hello world\n"
  320. " line 2\r"
  321. " line 3\r\n"
  322. " line 4\n\r"
  323. " line 5\r-->";
  324. XMLDocument doc;
  325. doc.Parse( test );
  326. doc.Print();
  327. }
  328. {
  329. static const char* test = "<element>Text before.</element>";
  330. XMLDocument doc;
  331. doc.Parse( test );
  332. XMLElement* root = doc.FirstChildElement();
  333. XMLElement* newElement = doc.NewElement( "Subelement" );
  334. root->InsertEndChild( newElement );
  335. doc.Print();
  336. }
  337. {
  338. XMLDocument* doc = new XMLDocument();
  339. static const char* test = "<element><sub/></element>";
  340. doc->Parse( test );
  341. delete doc;
  342. }
  343. {
  344. // Test: Programmatic DOM
  345. // Build:
  346. // <element>
  347. // <!--comment-->
  348. // <sub attrib="1" />
  349. // <sub attrib="2" />
  350. // <sub attrib="3" >& Text!</sub>
  351. // <element>
  352. XMLDocument* doc = new XMLDocument();
  353. XMLNode* element = doc->InsertEndChild( doc->NewElement( "element" ) );
  354. XMLElement* sub[3] = { doc->NewElement( "sub" ), doc->NewElement( "sub" ), doc->NewElement( "sub" ) };
  355. for( int i=0; i<3; ++i ) {
  356. sub[i]->SetAttribute( "attrib", i );
  357. }
  358. element->InsertEndChild( sub[2] );
  359. XMLNode* comment = element->InsertFirstChild( doc->NewComment( "comment" ) );
  360. comment->SetUserData((void*)2);
  361. element->InsertAfterChild( comment, sub[0] );
  362. element->InsertAfterChild( sub[0], sub[1] );
  363. sub[2]->InsertFirstChild( doc->NewText( "& Text!" ));
  364. doc->Print();
  365. XMLTest( "Programmatic DOM", "comment", doc->FirstChildElement( "element" )->FirstChild()->Value() );
  366. XMLTest( "Programmatic DOM", "0", doc->FirstChildElement( "element" )->FirstChildElement()->Attribute( "attrib" ) );
  367. XMLTest( "Programmatic DOM", 2, doc->FirstChildElement()->LastChildElement( "sub" )->IntAttribute( "attrib" ) );
  368. XMLTest( "Programmatic DOM", "& Text!",
  369. doc->FirstChildElement()->LastChildElement( "sub" )->FirstChild()->ToText()->Value() );
  370. XMLTest("User data", (void*)2 == comment->GetUserData(), true, false);
  371. // And now deletion:
  372. element->DeleteChild( sub[2] );
  373. doc->DeleteNode( comment );
  374. element->FirstChildElement()->SetAttribute( "attrib", true );
  375. element->LastChildElement()->DeleteAttribute( "attrib" );
  376. XMLTest( "Programmatic DOM", true, doc->FirstChildElement()->FirstChildElement()->BoolAttribute( "attrib" ) );
  377. int value1 = 10;
  378. int value2 = doc->FirstChildElement()->LastChildElement()->IntAttribute( "attrib", 10 );
  379. int result = doc->FirstChildElement()->LastChildElement()->QueryIntAttribute( "attrib", &value1 );
  380. XMLTest( "Programmatic DOM", result, (int)XML_NO_ATTRIBUTE );
  381. XMLTest( "Programmatic DOM", value1, 10 );
  382. XMLTest( "Programmatic DOM", value2, 10 );
  383. doc->Print();
  384. {
  385. XMLPrinter streamer;
  386. doc->Print( &streamer );
  387. printf( "%s", streamer.CStr() );
  388. }
  389. {
  390. XMLPrinter streamer( 0, true );
  391. doc->Print( &streamer );
  392. XMLTest( "Compact mode", "<element><sub attrib=\"true\"/><sub/></element>", streamer.CStr(), false );
  393. }
  394. doc->SaveFile( "./resources/out/pretty.xml" );
  395. doc->SaveFile( "./resources/out/compact.xml", true );
  396. delete doc;
  397. }
  398. {
  399. // Test: Dream
  400. // XML1 : 1,187,569 bytes in 31,209 allocations
  401. // XML2 : 469,073 bytes in 323 allocations
  402. //int newStart = gNew;
  403. XMLDocument doc;
  404. doc.LoadFile( "resources/dream.xml" );
  405. doc.SaveFile( "resources/out/dreamout.xml" );
  406. doc.PrintError();
  407. XMLTest( "Dream", "xml version=\"1.0\"",
  408. doc.FirstChild()->ToDeclaration()->Value() );
  409. XMLTest( "Dream", true, doc.FirstChild()->NextSibling()->ToUnknown() ? true : false );
  410. XMLTest( "Dream", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
  411. doc.FirstChild()->NextSibling()->ToUnknown()->Value() );
  412. XMLTest( "Dream", "And Robin shall restore amends.",
  413. doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
  414. XMLTest( "Dream", "And Robin shall restore amends.",
  415. doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
  416. XMLDocument doc2;
  417. doc2.LoadFile( "resources/out/dreamout.xml" );
  418. XMLTest( "Dream-out", "xml version=\"1.0\"",
  419. doc2.FirstChild()->ToDeclaration()->Value() );
  420. XMLTest( "Dream-out", true, doc2.FirstChild()->NextSibling()->ToUnknown() ? true : false );
  421. XMLTest( "Dream-out", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
  422. doc2.FirstChild()->NextSibling()->ToUnknown()->Value() );
  423. XMLTest( "Dream-out", "And Robin shall restore amends.",
  424. doc2.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
  425. //gNewTotal = gNew - newStart;
  426. }
  427. {
  428. const char* error = "<?xml version=\"1.0\" standalone=\"no\" ?>\n"
  429. "<passages count=\"006\" formatversion=\"20020620\">\n"
  430. " <wrong error>\n"
  431. "</passages>";
  432. XMLDocument doc;
  433. doc.Parse( error );
  434. XMLTest( "Bad XML", doc.ErrorID(), XML_ERROR_PARSING_ATTRIBUTE );
  435. }
  436. {
  437. const char* str = "<doc attr0='1' attr1='2.0' attr2='foo' />";
  438. XMLDocument doc;
  439. doc.Parse( str );
  440. XMLElement* ele = doc.FirstChildElement();
  441. int iVal, result;
  442. double dVal;
  443. result = ele->QueryDoubleAttribute( "attr0", &dVal );
  444. XMLTest( "Query attribute: int as double", result, (int)XML_SUCCESS);
  445. XMLTest( "Query attribute: int as double", (int)dVal, 1 );
  446. XMLTest( "Query attribute: int as double", (int)ele->DoubleAttribute("attr0"), 1);
  447. result = ele->QueryDoubleAttribute( "attr1", &dVal );
  448. XMLTest( "Query attribute: double as double", result, (int)XML_SUCCESS);
  449. XMLTest( "Query attribute: double as double", dVal, 2.0 );
  450. XMLTest( "Query attribute: double as double", ele->DoubleAttribute("attr1"), 2.0 );
  451. result = ele->QueryIntAttribute( "attr1", &iVal );
  452. XMLTest( "Query attribute: double as int", result, (int)XML_SUCCESS);
  453. XMLTest( "Query attribute: double as int", iVal, 2 );
  454. result = ele->QueryIntAttribute( "attr2", &iVal );
  455. XMLTest( "Query attribute: not a number", result, (int)XML_WRONG_ATTRIBUTE_TYPE );
  456. XMLTest( "Query attribute: not a number", ele->DoubleAttribute("attr2", 4.0), 4.0 );
  457. result = ele->QueryIntAttribute( "bar", &iVal );
  458. XMLTest( "Query attribute: does not exist", result, (int)XML_NO_ATTRIBUTE );
  459. XMLTest( "Query attribute: does not exist", ele->BoolAttribute("bar", true), true );
  460. }
  461. {
  462. const char* str = "<doc/>";
  463. XMLDocument doc;
  464. doc.Parse( str );
  465. XMLElement* ele = doc.FirstChildElement();
  466. int iVal, iVal2;
  467. double dVal, dVal2;
  468. ele->SetAttribute( "str", "strValue" );
  469. ele->SetAttribute( "int", 1 );
  470. ele->SetAttribute( "double", -1.0 );
  471. const char* cStr = ele->Attribute( "str" );
  472. ele->QueryIntAttribute( "int", &iVal );
  473. ele->QueryDoubleAttribute( "double", &dVal );
  474. ele->QueryAttribute( "int", &iVal2 );
  475. ele->QueryAttribute( "double", &dVal2 );
  476. XMLTest( "Attribute match test", ele->Attribute( "str", "strValue" ), "strValue" );
  477. XMLTest( "Attribute round trip. c-string.", "strValue", cStr );
  478. XMLTest( "Attribute round trip. int.", 1, iVal );
  479. XMLTest( "Attribute round trip. double.", -1, (int)dVal );
  480. XMLTest( "Alternate query", true, iVal == iVal2 );
  481. XMLTest( "Alternate query", true, dVal == dVal2 );
  482. XMLTest( "Alternate query", true, iVal == ele->IntAttribute("int") );
  483. XMLTest( "Alternate query", true, dVal == ele->DoubleAttribute("double") );
  484. }
  485. {
  486. XMLDocument doc;
  487. doc.LoadFile( "resources/utf8test.xml" );
  488. // Get the attribute "value" from the "Russian" element and check it.
  489. XMLElement* element = doc.FirstChildElement( "document" )->FirstChildElement( "Russian" );
  490. const unsigned char correctValue[] = { 0xd1U, 0x86U, 0xd0U, 0xb5U, 0xd0U, 0xbdU, 0xd0U, 0xbdU,
  491. 0xd0U, 0xbeU, 0xd1U, 0x81U, 0xd1U, 0x82U, 0xd1U, 0x8cU, 0 };
  492. XMLTest( "UTF-8: Russian value.", (const char*)correctValue, element->Attribute( "value" ) );
  493. const unsigned char russianElementName[] = { 0xd0U, 0xa0U, 0xd1U, 0x83U,
  494. 0xd1U, 0x81U, 0xd1U, 0x81U,
  495. 0xd0U, 0xbaU, 0xd0U, 0xb8U,
  496. 0xd0U, 0xb9U, 0 };
  497. const char russianText[] = "<\xD0\xB8\xD0\xBC\xD0\xB5\xD0\xB5\xD1\x82>";
  498. XMLText* text = doc.FirstChildElement( "document" )->FirstChildElement( (const char*) russianElementName )->FirstChild()->ToText();
  499. XMLTest( "UTF-8: Browsing russian element name.",
  500. russianText,
  501. text->Value() );
  502. // Now try for a round trip.
  503. doc.SaveFile( "resources/out/utf8testout.xml" );
  504. // Check the round trip.
  505. int okay = 0;
  506. FILE* saved = fopen( "resources/out/utf8testout.xml", "r" );
  507. FILE* verify = fopen( "resources/utf8testverify.xml", "r" );
  508. if ( saved && verify )
  509. {
  510. okay = 1;
  511. char verifyBuf[256];
  512. while ( fgets( verifyBuf, 256, verify ) )
  513. {
  514. char savedBuf[256];
  515. fgets( savedBuf, 256, saved );
  516. NullLineEndings( verifyBuf );
  517. NullLineEndings( savedBuf );
  518. if ( strcmp( verifyBuf, savedBuf ) )
  519. {
  520. printf( "verify:%s<\n", verifyBuf );
  521. printf( "saved :%s<\n", savedBuf );
  522. okay = 0;
  523. break;
  524. }
  525. }
  526. }
  527. if ( saved )
  528. fclose( saved );
  529. if ( verify )
  530. fclose( verify );
  531. XMLTest( "UTF-8: Verified multi-language round trip.", 1, okay );
  532. }
  533. // --------GetText()-----------
  534. {
  535. const char* str = "<foo>This is text</foo>";
  536. XMLDocument doc;
  537. doc.Parse( str );
  538. const XMLElement* element = doc.RootElement();
  539. XMLTest( "GetText() normal use.", "This is text", element->GetText() );
  540. str = "<foo><b>This is text</b></foo>";
  541. doc.Parse( str );
  542. element = doc.RootElement();
  543. XMLTest( "GetText() contained element.", element->GetText() == 0, true );
  544. }
  545. // --------SetText()-----------
  546. {
  547. const char* str = "<foo></foo>";
  548. XMLDocument doc;
  549. doc.Parse( str );
  550. XMLElement* element = doc.RootElement();
  551. element->SetText("darkness.");
  552. XMLTest( "SetText() normal use (open/close).", "darkness.", element->GetText() );
  553. element->SetText("blue flame.");
  554. XMLTest( "SetText() replace.", "blue flame.", element->GetText() );
  555. str = "<foo/>";
  556. doc.Parse( str );
  557. element = doc.RootElement();
  558. element->SetText("The driver");
  559. XMLTest( "SetText() normal use. (self-closing)", "The driver", element->GetText() );
  560. element->SetText("<b>horses</b>");
  561. XMLTest( "SetText() replace with tag-like text.", "<b>horses</b>", element->GetText() );
  562. //doc.Print();
  563. str = "<foo><bar>Text in nested element</bar></foo>";
  564. doc.Parse( str );
  565. element = doc.RootElement();
  566. element->SetText("wolves");
  567. XMLTest( "SetText() prefix to nested non-text children.", "wolves", element->GetText() );
  568. str = "<foo/>";
  569. doc.Parse( str );
  570. element = doc.RootElement();
  571. element->SetText( "str" );
  572. XMLTest( "SetText types", "str", element->GetText() );
  573. element->SetText( 1 );
  574. XMLTest( "SetText types", "1", element->GetText() );
  575. element->SetText( 1U );
  576. XMLTest( "SetText types", "1", element->GetText() );
  577. element->SetText( true );
  578. XMLTest( "SetText types", "true", element->GetText() );
  579. element->SetText( 1.5f );
  580. XMLTest( "SetText types", "1.5", element->GetText() );
  581. element->SetText( 1.5 );
  582. XMLTest( "SetText types", "1.5", element->GetText() );
  583. }
  584. // ---------- Attributes ---------
  585. {
  586. static const int64_t BIG = -123456789012345678;
  587. XMLDocument doc;
  588. XMLElement* element = doc.NewElement("element");
  589. doc.InsertFirstChild(element);
  590. {
  591. element->SetAttribute("attrib", int(-100));
  592. int v = 0;
  593. element->QueryIntAttribute("attrib", &v);
  594. XMLTest("Attribute: int", -100, v, true);
  595. element->QueryAttribute("attrib", &v);
  596. XMLTest("Attribute: int", -100, v, true);
  597. XMLTest("Attribute: int", -100, element->IntAttribute("attrib"), true);
  598. }
  599. {
  600. element->SetAttribute("attrib", unsigned(100));
  601. unsigned v = 0;
  602. element->QueryUnsignedAttribute("attrib", &v);
  603. XMLTest("Attribute: unsigned", unsigned(100), v, true);
  604. element->QueryAttribute("attrib", &v);
  605. XMLTest("Attribute: unsigned", unsigned(100), v, true);
  606. XMLTest("Attribute: unsigned", unsigned(100), element->UnsignedAttribute("attrib"), true);
  607. }
  608. {
  609. element->SetAttribute("attrib", BIG);
  610. int64_t v = 0;
  611. element->QueryInt64Attribute("attrib", &v);
  612. XMLTest("Attribute: int64_t", BIG, v, true);
  613. element->QueryAttribute("attrib", &v);
  614. XMLTest("Attribute: int64_t", BIG, v, true);
  615. XMLTest("Attribute: int64_t", BIG, element->Int64Attribute("attrib"), true);
  616. }
  617. {
  618. element->SetAttribute("attrib", true);
  619. bool v = false;
  620. element->QueryBoolAttribute("attrib", &v);
  621. XMLTest("Attribute: bool", true, v, true);
  622. element->QueryAttribute("attrib", &v);
  623. XMLTest("Attribute: bool", true, v, true);
  624. XMLTest("Attribute: bool", true, element->BoolAttribute("attrib"), true);
  625. }
  626. {
  627. element->SetAttribute("attrib", true);
  628. const char* result = element->Attribute("attrib");
  629. XMLTest("Bool true is 'true'", "true", result);
  630. XMLUtil::SetBoolSerialization("1", "0");
  631. element->SetAttribute("attrib", true);
  632. result = element->Attribute("attrib");
  633. XMLTest("Bool true is '1'", "1", result);
  634. XMLUtil::SetBoolSerialization(0, 0);
  635. }
  636. {
  637. element->SetAttribute("attrib", 100.0);
  638. double v = 0;
  639. element->QueryDoubleAttribute("attrib", &v);
  640. XMLTest("Attribute: double", 100.0, v, true);
  641. element->QueryAttribute("attrib", &v);
  642. XMLTest("Attribute: double", 100.0, v, true);
  643. XMLTest("Attribute: double", 100.0, element->DoubleAttribute("attrib"), true);
  644. }
  645. {
  646. element->SetAttribute("attrib", 100.0f);
  647. float v = 0;
  648. element->QueryFloatAttribute("attrib", &v);
  649. XMLTest("Attribute: float", 100.0f, v, true);
  650. element->QueryAttribute("attrib", &v);
  651. XMLTest("Attribute: float", 100.0f, v, true);
  652. XMLTest("Attribute: float", 100.0f, element->FloatAttribute("attrib"), true);
  653. }
  654. {
  655. element->SetText(BIG);
  656. int64_t v = 0;
  657. element->QueryInt64Text(&v);
  658. XMLTest("Element: int64_t", BIG, v, true);
  659. }
  660. }
  661. // ---------- XMLPrinter stream mode ------
  662. {
  663. {
  664. FILE* printerfp = fopen("resources/printer.xml", "w");
  665. XMLPrinter printer(printerfp);
  666. printer.OpenElement("foo");
  667. printer.PushAttribute("attrib-text", "text");
  668. printer.PushAttribute("attrib-int", int(1));
  669. printer.PushAttribute("attrib-unsigned", unsigned(2));
  670. printer.PushAttribute("attrib-int64", int64_t(3));
  671. printer.PushAttribute("attrib-bool", true);
  672. printer.PushAttribute("attrib-double", 4.0);
  673. printer.CloseElement();
  674. fclose(printerfp);
  675. }
  676. {
  677. XMLDocument doc;
  678. doc.LoadFile("resources/printer.xml");
  679. XMLTest("XMLPrinter Stream mode: load", doc.ErrorID(), XML_SUCCESS, true);
  680. const XMLDocument& cdoc = doc;
  681. const XMLAttribute* attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-text");
  682. XMLTest("attrib-text", "text", attrib->Value(), true);
  683. attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int");
  684. XMLTest("attrib-int", int(1), attrib->IntValue(), true);
  685. attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-unsigned");
  686. XMLTest("attrib-unsigned", unsigned(2), attrib->UnsignedValue(), true);
  687. attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int64");
  688. XMLTest("attrib-int64", int64_t(3), attrib->Int64Value(), true);
  689. attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-bool");
  690. XMLTest("attrib-bool", true, attrib->BoolValue(), true);
  691. attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-double");
  692. XMLTest("attrib-double", 4.0, attrib->DoubleValue(), true);
  693. }
  694. }
  695. // ---------- CDATA ---------------
  696. {
  697. const char* str = "<xmlElement>"
  698. "<![CDATA["
  699. "I am > the rules!\n"
  700. "...since I make symbolic puns"
  701. "]]>"
  702. "</xmlElement>";
  703. XMLDocument doc;
  704. doc.Parse( str );
  705. doc.Print();
  706. XMLTest( "CDATA parse.", doc.FirstChildElement()->FirstChild()->Value(),
  707. "I am > the rules!\n...since I make symbolic puns",
  708. false );
  709. }
  710. // ----------- CDATA -------------
  711. {
  712. const char* str = "<xmlElement>"
  713. "<![CDATA["
  714. "<b>I am > the rules!</b>\n"
  715. "...since I make symbolic puns"
  716. "]]>"
  717. "</xmlElement>";
  718. XMLDocument doc;
  719. doc.Parse( str );
  720. doc.Print();
  721. XMLTest( "CDATA parse. [ tixml1:1480107 ]", doc.FirstChildElement()->FirstChild()->Value(),
  722. "<b>I am > the rules!</b>\n...since I make symbolic puns",
  723. false );
  724. }
  725. // InsertAfterChild causes crash.
  726. {
  727. // InsertBeforeChild and InsertAfterChild causes crash.
  728. XMLDocument doc;
  729. XMLElement* parent = doc.NewElement( "Parent" );
  730. doc.InsertFirstChild( parent );
  731. XMLElement* childText0 = doc.NewElement( "childText0" );
  732. XMLElement* childText1 = doc.NewElement( "childText1" );
  733. XMLNode* childNode0 = parent->InsertEndChild( childText0 );
  734. XMLNode* childNode1 = parent->InsertAfterChild( childNode0, childText1 );
  735. XMLTest( "Test InsertAfterChild on empty node. ", ( childNode1 == parent->LastChild() ), true );
  736. }
  737. {
  738. // Entities not being written correctly.
  739. // From Lynn Allen
  740. const char* passages =
  741. "<?xml version=\"1.0\" standalone=\"no\" ?>"
  742. "<passages count=\"006\" formatversion=\"20020620\">"
  743. "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
  744. " It also has &lt;, &gt;, and &amp;, as well as a fake copyright &#xA9;.\"> </psg>"
  745. "</passages>";
  746. XMLDocument doc;
  747. doc.Parse( passages );
  748. XMLElement* psg = doc.RootElement()->FirstChildElement();
  749. const char* context = psg->Attribute( "context" );
  750. const char* expected = "Line 5 has \"quotation marks\" and 'apostrophe marks'. It also has <, >, and &, as well as a fake copyright \xC2\xA9.";
  751. XMLTest( "Entity transformation: read. ", expected, context, true );
  752. FILE* textfile = fopen( "resources/out/textfile.txt", "w" );
  753. if ( textfile )
  754. {
  755. XMLPrinter streamer( textfile );
  756. psg->Accept( &streamer );
  757. fclose( textfile );
  758. }
  759. textfile = fopen( "resources/out/textfile.txt", "r" );
  760. TIXMLASSERT( textfile );
  761. if ( textfile )
  762. {
  763. char buf[ 1024 ];
  764. fgets( buf, 1024, textfile );
  765. XMLTest( "Entity transformation: write. ",
  766. "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
  767. " It also has &lt;, &gt;, and &amp;, as well as a fake copyright \xC2\xA9.\"/>\n",
  768. buf, false );
  769. fclose( textfile );
  770. }
  771. }
  772. {
  773. // Suppress entities.
  774. const char* passages =
  775. "<?xml version=\"1.0\" standalone=\"no\" ?>"
  776. "<passages count=\"006\" formatversion=\"20020620\">"
  777. "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.\">Crazy &ttk;</psg>"
  778. "</passages>";
  779. XMLDocument doc( false );
  780. doc.Parse( passages );
  781. XMLTest( "No entity parsing.", doc.FirstChildElement()->FirstChildElement()->Attribute( "context" ),
  782. "Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;." );
  783. XMLTest( "No entity parsing.", doc.FirstChildElement()->FirstChildElement()->FirstChild()->Value(),
  784. "Crazy &ttk;" );
  785. doc.Print();
  786. }
  787. {
  788. const char* test = "<?xml version='1.0'?><a.elem xmi.version='2.0'/>";
  789. XMLDocument doc;
  790. doc.Parse( test );
  791. XMLTest( "dot in names", doc.Error(), false );
  792. XMLTest( "dot in names", doc.FirstChildElement()->Name(), "a.elem" );
  793. XMLTest( "dot in names", doc.FirstChildElement()->Attribute( "xmi.version" ), "2.0" );
  794. }
  795. {
  796. const char* test = "<element><Name>1.1 Start easy ignore fin thickness&#xA;</Name></element>";
  797. XMLDocument doc;
  798. doc.Parse( test );
  799. XMLText* text = doc.FirstChildElement()->FirstChildElement()->FirstChild()->ToText();
  800. XMLTest( "Entity with one digit.",
  801. text->Value(), "1.1 Start easy ignore fin thickness\n",
  802. false );
  803. }
  804. {
  805. // DOCTYPE not preserved (950171)
  806. //
  807. const char* doctype =
  808. "<?xml version=\"1.0\" ?>"
  809. "<!DOCTYPE PLAY SYSTEM 'play.dtd'>"
  810. "<!ELEMENT title (#PCDATA)>"
  811. "<!ELEMENT books (title,authors)>"
  812. "<element />";
  813. XMLDocument doc;
  814. doc.Parse( doctype );
  815. doc.SaveFile( "resources/out/test7.xml" );
  816. doc.DeleteChild( doc.RootElement() );
  817. doc.LoadFile( "resources/out/test7.xml" );
  818. doc.Print();
  819. const XMLUnknown* decl = doc.FirstChild()->NextSibling()->ToUnknown();
  820. XMLTest( "Correct value of unknown.", "DOCTYPE PLAY SYSTEM 'play.dtd'", decl->Value() );
  821. }
  822. {
  823. // Comments do not stream out correctly.
  824. const char* doctype =
  825. "<!-- Somewhat<evil> -->";
  826. XMLDocument doc;
  827. doc.Parse( doctype );
  828. XMLComment* comment = doc.FirstChild()->ToComment();
  829. XMLTest( "Comment formatting.", " Somewhat<evil> ", comment->Value() );
  830. }
  831. {
  832. // Double attributes
  833. const char* doctype = "<element attr='red' attr='blue' />";
  834. XMLDocument doc;
  835. doc.Parse( doctype );
  836. XMLTest( "Parsing repeated attributes.", XML_ERROR_PARSING_ATTRIBUTE, doc.ErrorID() ); // is an error to tinyxml (didn't use to be, but caused issues)
  837. doc.PrintError();
  838. }
  839. {
  840. // Embedded null in stream.
  841. const char* doctype = "<element att\0r='red' attr='blue' />";
  842. XMLDocument doc;
  843. doc.Parse( doctype );
  844. XMLTest( "Embedded null throws error.", true, doc.Error() );
  845. }
  846. {
  847. // Empty documents should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
  848. const char* str = "";
  849. XMLDocument doc;
  850. doc.Parse( str );
  851. XMLTest( "Empty document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
  852. }
  853. {
  854. // Documents with all whitespaces should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
  855. const char* str = " ";
  856. XMLDocument doc;
  857. doc.Parse( str );
  858. XMLTest( "All whitespaces document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
  859. }
  860. {
  861. // Low entities
  862. XMLDocument doc;
  863. doc.Parse( "<test>&#x0e;</test>" );
  864. const char result[] = { 0x0e, 0 };
  865. XMLTest( "Low entities.", doc.FirstChildElement()->GetText(), result );
  866. doc.Print();
  867. }
  868. {
  869. // Attribute values with trailing quotes not handled correctly
  870. XMLDocument doc;
  871. doc.Parse( "<foo attribute=bar\" />" );
  872. XMLTest( "Throw error with bad end quotes.", doc.Error(), true );
  873. }
  874. {
  875. // [ 1663758 ] Failure to report error on bad XML
  876. XMLDocument xml;
  877. xml.Parse("<x>");
  878. XMLTest("Missing end tag at end of input", xml.Error(), true);
  879. xml.Parse("<x> ");
  880. XMLTest("Missing end tag with trailing whitespace", xml.Error(), true);
  881. xml.Parse("<x></y>");
  882. XMLTest("Mismatched tags", xml.ErrorID(), XML_ERROR_MISMATCHED_ELEMENT);
  883. }
  884. {
  885. // [ 1475201 ] TinyXML parses entities in comments
  886. XMLDocument xml;
  887. xml.Parse("<!-- declarations for <head> & <body> -->"
  888. "<!-- far &amp; away -->" );
  889. XMLNode* e0 = xml.FirstChild();
  890. XMLNode* e1 = e0->NextSibling();
  891. XMLComment* c0 = e0->ToComment();
  892. XMLComment* c1 = e1->ToComment();
  893. XMLTest( "Comments ignore entities.", " declarations for <head> & <body> ", c0->Value(), true );
  894. XMLTest( "Comments ignore entities.", " far &amp; away ", c1->Value(), true );
  895. }
  896. {
  897. XMLDocument xml;
  898. xml.Parse( "<Parent>"
  899. "<child1 att=''/>"
  900. "<!-- With this comment, child2 will not be parsed! -->"
  901. "<child2 att=''/>"
  902. "</Parent>" );
  903. xml.Print();
  904. int count = 0;
  905. for( XMLNode* ele = xml.FirstChildElement( "Parent" )->FirstChild();
  906. ele;
  907. ele = ele->NextSibling() )
  908. {
  909. ++count;
  910. }
  911. XMLTest( "Comments iterate correctly.", 3, count );
  912. }
  913. {
  914. // trying to repro ]1874301]. If it doesn't go into an infinite loop, all is well.
  915. unsigned char buf[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?><feed><![CDATA[Test XMLblablablalblbl";
  916. buf[60] = 239;
  917. buf[61] = 0;
  918. XMLDocument doc;
  919. doc.Parse( (const char*)buf);
  920. }
  921. {
  922. // bug 1827248 Error while parsing a little bit malformed file
  923. // Actually not malformed - should work.
  924. XMLDocument xml;
  925. xml.Parse( "<attributelist> </attributelist >" );
  926. XMLTest( "Handle end tag whitespace", false, xml.Error() );
  927. }
  928. {
  929. // This one must not result in an infinite loop
  930. XMLDocument xml;
  931. xml.Parse( "<infinite>loop" );
  932. XMLTest( "Infinite loop test.", true, true );
  933. }
  934. #endif
  935. {
  936. const char* pub = "<?xml version='1.0'?> <element><sub/></element> <!--comment--> <!DOCTYPE>";
  937. XMLDocument doc;
  938. doc.Parse( pub );
  939. XMLDocument clone;
  940. for( const XMLNode* node=doc.FirstChild(); node; node=node->NextSibling() ) {
  941. XMLNode* copy = node->ShallowClone( &clone );
  942. clone.InsertEndChild( copy );
  943. }
  944. clone.Print();
  945. int count=0;
  946. const XMLNode* a=clone.FirstChild();
  947. const XMLNode* b=doc.FirstChild();
  948. for( ; a && b; a=a->NextSibling(), b=b->NextSibling() ) {
  949. ++count;
  950. XMLTest( "Clone and Equal", true, a->ShallowEqual( b ));
  951. }
  952. XMLTest( "Clone and Equal", 4, count );
  953. }
  954. {
  955. // Deep Cloning of root element.
  956. XMLDocument doc2;
  957. XMLPrinter printer1;
  958. {
  959. // Make sure doc1 is deleted before we test doc2
  960. const char* xml =
  961. "<root>"
  962. " <child1 foo='bar'/>"
  963. " <!-- comment thing -->"
  964. " <child2 val='1'>Text</child2>"
  965. "</root>";
  966. XMLDocument doc;
  967. doc.Parse(xml);
  968. doc.Print(&printer1);
  969. XMLNode* root = doc.RootElement()->DeepClone(&doc2);
  970. doc2.InsertFirstChild(root);
  971. }
  972. XMLPrinter printer2;
  973. doc2.Print(&printer2);
  974. XMLTest("Deep clone of element.", printer1.CStr(), printer2.CStr(), true);
  975. }
  976. {
  977. // Deep Cloning of sub element.
  978. XMLDocument doc2;
  979. XMLPrinter printer1;
  980. {
  981. // Make sure doc1 is deleted before we test doc2
  982. const char* xml =
  983. "<?xml version ='1.0'?>"
  984. "<root>"
  985. " <child1 foo='bar'/>"
  986. " <!-- comment thing -->"
  987. " <child2 val='1'>Text</child2>"
  988. "</root>";
  989. XMLDocument doc;
  990. doc.Parse(xml);
  991. const XMLElement* subElement = doc.FirstChildElement("root")->FirstChildElement("child2");
  992. subElement->Accept(&printer1);
  993. XMLNode* clonedSubElement = subElement->DeepClone(&doc2);
  994. doc2.InsertFirstChild(clonedSubElement);
  995. }
  996. XMLPrinter printer2;
  997. doc2.Print(&printer2);
  998. XMLTest("Deep clone of sub-element.", printer1.CStr(), printer2.CStr(), true);
  999. }
  1000. {
  1001. // Deep cloning of document.
  1002. XMLDocument doc2;
  1003. XMLPrinter printer1;
  1004. {
  1005. // Make sure doc1 is deleted before we test doc2
  1006. const char* xml =
  1007. "<?xml version ='1.0'?>"
  1008. "<!-- Top level comment. -->"
  1009. "<root>"
  1010. " <child1 foo='bar'/>"
  1011. " <!-- comment thing -->"
  1012. " <child2 val='1'>Text</child2>"
  1013. "</root>";
  1014. XMLDocument doc;
  1015. doc.Parse(xml);
  1016. doc.Print(&printer1);
  1017. doc.DeepCopy(&doc2);
  1018. }
  1019. XMLPrinter printer2;
  1020. doc2.Print(&printer2);
  1021. XMLTest("DeepCopy of document.", printer1.CStr(), printer2.CStr(), true);
  1022. }
  1023. {
  1024. // This shouldn't crash.
  1025. XMLDocument doc;
  1026. if(XML_SUCCESS != doc.LoadFile( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ))
  1027. {
  1028. doc.PrintError();
  1029. }
  1030. XMLTest( "Error in snprinf handling.", true, doc.Error() );
  1031. }
  1032. {
  1033. // Attribute ordering.
  1034. static const char* xml = "<element attrib1=\"1\" attrib2=\"2\" attrib3=\"3\" />";
  1035. XMLDocument doc;
  1036. doc.Parse( xml );
  1037. XMLElement* ele = doc.FirstChildElement();
  1038. const XMLAttribute* a = ele->FirstAttribute();
  1039. XMLTest( "Attribute order", "1", a->Value() );
  1040. a = a->Next();
  1041. XMLTest( "Attribute order", "2", a->Value() );
  1042. a = a->Next();
  1043. XMLTest( "Attribute order", "3", a->Value() );
  1044. XMLTest( "Attribute order", "attrib3", a->Name() );
  1045. ele->DeleteAttribute( "attrib2" );
  1046. a = ele->FirstAttribute();
  1047. XMLTest( "Attribute order", "1", a->Value() );
  1048. a = a->Next();
  1049. XMLTest( "Attribute order", "3", a->Value() );
  1050. ele->DeleteAttribute( "attrib1" );
  1051. ele->DeleteAttribute( "attrib3" );
  1052. XMLTest( "Attribute order (empty)", false, ele->FirstAttribute() ? true : false );
  1053. }
  1054. {
  1055. // Make sure an attribute with a space in it succeeds.
  1056. static const char* xml0 = "<element attribute1= \"Test Attribute\"/>";
  1057. static const char* xml1 = "<element attribute1 =\"Test Attribute\"/>";
  1058. static const char* xml2 = "<element attribute1 = \"Test Attribute\"/>";
  1059. XMLDocument doc0;
  1060. doc0.Parse( xml0 );
  1061. XMLDocument doc1;
  1062. doc1.Parse( xml1 );
  1063. XMLDocument doc2;
  1064. doc2.Parse( xml2 );
  1065. XMLElement* ele = 0;
  1066. ele = doc0.FirstChildElement();
  1067. XMLTest( "Attribute with space #1", "Test Attribute", ele->Attribute( "attribute1" ) );
  1068. ele = doc1.FirstChildElement();
  1069. XMLTest( "Attribute with space #2", "Test Attribute", ele->Attribute( "attribute1" ) );
  1070. ele = doc2.FirstChildElement();
  1071. XMLTest( "Attribute with space #3", "Test Attribute", ele->Attribute( "attribute1" ) );
  1072. }
  1073. {
  1074. // Make sure we don't go into an infinite loop.
  1075. static const char* xml = "<doc><element attribute='attribute'/><element attribute='attribute'/></doc>";
  1076. XMLDocument doc;
  1077. doc.Parse( xml );
  1078. XMLElement* ele0 = doc.FirstChildElement()->FirstChildElement();
  1079. XMLElement* ele1 = ele0->NextSiblingElement();
  1080. bool equal = ele0->ShallowEqual( ele1 );
  1081. XMLTest( "Infinite loop in shallow equal.", true, equal );
  1082. }
  1083. // -------- Handles ------------
  1084. {
  1085. static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
  1086. XMLDocument doc;
  1087. doc.Parse( xml );
  1088. XMLElement* ele = XMLHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
  1089. XMLTest( "Handle, success, mutable", ele->Value(), "sub" );
  1090. XMLHandle docH( doc );
  1091. ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
  1092. XMLTest( "Handle, dne, mutable", false, ele != 0 );
  1093. }
  1094. {
  1095. static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
  1096. XMLDocument doc;
  1097. doc.Parse( xml );
  1098. XMLConstHandle docH( doc );
  1099. const XMLElement* ele = docH.FirstChildElement( "element" ).FirstChild().ToElement();
  1100. XMLTest( "Handle, success, const", ele->Value(), "sub" );
  1101. ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
  1102. XMLTest( "Handle, dne, const", false, ele != 0 );
  1103. }
  1104. {
  1105. // Default Declaration & BOM
  1106. XMLDocument doc;
  1107. doc.InsertEndChild( doc.NewDeclaration() );
  1108. doc.SetBOM( true );
  1109. XMLPrinter printer;
  1110. doc.Print( &printer );
  1111. static const char* result = "\xef\xbb\xbf<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
  1112. XMLTest( "BOM and default declaration", printer.CStr(), result, false );
  1113. XMLTest( "CStrSize", printer.CStrSize(), 42, false );
  1114. }
  1115. {
  1116. const char* xml = "<ipxml ws='1'><info bla=' /></ipxml>";
  1117. XMLDocument doc;
  1118. doc.Parse( xml );
  1119. XMLTest( "Ill formed XML", true, doc.Error() );
  1120. }
  1121. // QueryXYZText
  1122. {
  1123. const char* xml = "<point> <x>1.2</x> <y>1</y> <z>38</z> <valid>true</valid> </point>";
  1124. XMLDocument doc;
  1125. doc.Parse( xml );
  1126. const XMLElement* pointElement = doc.RootElement();
  1127. int intValue = 0;
  1128. unsigned unsignedValue = 0;
  1129. float floatValue = 0;
  1130. double doubleValue = 0;
  1131. bool boolValue = false;
  1132. pointElement->FirstChildElement( "y" )->QueryIntText( &intValue );
  1133. pointElement->FirstChildElement( "y" )->QueryUnsignedText( &unsignedValue );
  1134. pointElement->FirstChildElement( "x" )->QueryFloatText( &floatValue );
  1135. pointElement->FirstChildElement( "x" )->QueryDoubleText( &doubleValue );
  1136. pointElement->FirstChildElement( "valid" )->QueryBoolText( &boolValue );
  1137. XMLTest( "QueryIntText", intValue, 1, false );
  1138. XMLTest( "QueryUnsignedText", unsignedValue, (unsigned)1, false );
  1139. XMLTest( "QueryFloatText", floatValue, 1.2f, false );
  1140. XMLTest( "QueryDoubleText", doubleValue, 1.2, false );
  1141. XMLTest( "QueryBoolText", boolValue, true, false );
  1142. }
  1143. {
  1144. const char* xml = "<element><_sub/><:sub/><sub:sub/><sub-sub/></element>";
  1145. XMLDocument doc;
  1146. doc.Parse( xml );
  1147. XMLTest( "Non-alpha element lead letter parses.", doc.Error(), false );
  1148. }
  1149. {
  1150. const char* xml = "<element _attr1=\"foo\" :attr2=\"bar\"></element>";
  1151. XMLDocument doc;
  1152. doc.Parse( xml );
  1153. XMLTest("Non-alpha attribute lead character parses.", doc.Error(), false);
  1154. }
  1155. {
  1156. const char* xml = "<3lement></3lement>";
  1157. XMLDocument doc;
  1158. doc.Parse( xml );
  1159. XMLTest("Element names with lead digit fail to parse.", doc.Error(), true);
  1160. }
  1161. {
  1162. const char* xml = "<element/>WOA THIS ISN'T GOING TO PARSE";
  1163. XMLDocument doc;
  1164. doc.Parse( xml, 10 );
  1165. XMLTest( "Set length of incoming data", doc.Error(), false );
  1166. }
  1167. {
  1168. XMLDocument doc;
  1169. XMLTest( "Document is initially empty", doc.NoChildren(), true );
  1170. doc.Clear();
  1171. XMLTest( "Empty is empty after Clear()", doc.NoChildren(), true );
  1172. doc.LoadFile( "resources/dream.xml" );
  1173. XMLTest( "Document has something to Clear()", doc.NoChildren(), false );
  1174. doc.Clear();
  1175. XMLTest( "Document Clear()'s", doc.NoChildren(), true );
  1176. }
  1177. // ----------- Whitespace ------------
  1178. {
  1179. const char* xml = "<element>"
  1180. "<a> This \nis &apos; text &apos; </a>"
  1181. "<b> This is &apos; text &apos; \n</b>"
  1182. "<c>This is &apos; \n\n text &apos;</c>"
  1183. "</element>";
  1184. XMLDocument doc( true, COLLAPSE_WHITESPACE );
  1185. doc.Parse( xml );
  1186. const XMLElement* element = doc.FirstChildElement();
  1187. for( const XMLElement* parent = element->FirstChildElement();
  1188. parent;
  1189. parent = parent->NextSiblingElement() )
  1190. {
  1191. XMLTest( "Whitespace collapse", "This is ' text '", parent->GetText() );
  1192. }
  1193. }
  1194. #if 0
  1195. {
  1196. // Passes if assert doesn't fire.
  1197. XMLDocument xmlDoc;
  1198. xmlDoc.NewDeclaration();
  1199. xmlDoc.NewComment("Configuration file");
  1200. XMLElement *root = xmlDoc.NewElement("settings");
  1201. root->SetAttribute("version", 2);
  1202. }
  1203. #endif
  1204. {
  1205. const char* xml = "<element> </element>";
  1206. XMLDocument doc( true, COLLAPSE_WHITESPACE );
  1207. doc.Parse( xml );
  1208. XMLTest( "Whitespace all space", true, 0 == doc.FirstChildElement()->FirstChild() );
  1209. }
  1210. {
  1211. // An assert should not fire.
  1212. const char* xml = "<element/>";
  1213. XMLDocument doc;
  1214. doc.Parse( xml );
  1215. XMLElement* ele = doc.NewElement( "unused" ); // This will get cleaned up with the 'doc' going out of scope.
  1216. XMLTest( "Tracking unused elements", true, ele != 0, false );
  1217. }
  1218. {
  1219. const char* xml = "<parent><child>abc</child></parent>";
  1220. XMLDocument doc;
  1221. doc.Parse( xml );
  1222. XMLElement* ele = doc.FirstChildElement( "parent")->FirstChildElement( "child");
  1223. XMLPrinter printer;
  1224. ele->Accept( &printer );
  1225. XMLTest( "Printing of sub-element", "<child>abc</child>\n", printer.CStr(), false );
  1226. }
  1227. {
  1228. XMLDocument doc;
  1229. XMLError error = doc.LoadFile( "resources/empty.xml" );
  1230. XMLTest( "Loading an empty file", XML_ERROR_EMPTY_DOCUMENT, error );
  1231. XMLTest( "Loading an empty file and ErrorName as string", "XML_ERROR_EMPTY_DOCUMENT", doc.ErrorName() );
  1232. doc.PrintError();
  1233. }
  1234. {
  1235. // BOM preservation
  1236. static const char* xml_bom_preservation = "\xef\xbb\xbf<element/>\n";
  1237. {
  1238. XMLDocument doc;
  1239. XMLTest( "BOM preservation (parse)", XML_SUCCESS, doc.Parse( xml_bom_preservation ), false );
  1240. XMLPrinter printer;
  1241. doc.Print( &printer );
  1242. XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
  1243. doc.SaveFile( "resources/bomtest.xml" );
  1244. }
  1245. {
  1246. XMLDocument doc;
  1247. doc.LoadFile( "resources/bomtest.xml" );
  1248. XMLTest( "BOM preservation (load)", true, doc.HasBOM(), false );
  1249. XMLPrinter printer;
  1250. doc.Print( &printer );
  1251. XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
  1252. }
  1253. }
  1254. {
  1255. // Insertion with Removal
  1256. const char* xml = "<?xml version=\"1.0\" ?>"
  1257. "<root>"
  1258. "<one>"
  1259. "<subtree>"
  1260. "<elem>element 1</elem>text<!-- comment -->"
  1261. "</subtree>"
  1262. "</one>"
  1263. "<two/>"
  1264. "</root>";
  1265. const char* xmlInsideTwo = "<?xml version=\"1.0\" ?>"
  1266. "<root>"
  1267. "<one/>"
  1268. "<two>"
  1269. "<subtree>"
  1270. "<elem>element 1</elem>text<!-- comment -->"
  1271. "</subtree>"
  1272. "</two>"
  1273. "</root>";
  1274. const char* xmlAfterOne = "<?xml version=\"1.0\" ?>"
  1275. "<root>"
  1276. "<one/>"
  1277. "<subtree>"
  1278. "<elem>element 1</elem>text<!-- comment -->"
  1279. "</subtree>"
  1280. "<two/>"
  1281. "</root>";
  1282. const char* xmlAfterTwo = "<?xml version=\"1.0\" ?>"
  1283. "<root>"
  1284. "<one/>"
  1285. "<two/>"
  1286. "<subtree>"
  1287. "<elem>element 1</elem>text<!-- comment -->"
  1288. "</subtree>"
  1289. "</root>";
  1290. XMLDocument doc;
  1291. doc.Parse(xml);
  1292. XMLElement* subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
  1293. XMLElement* two = doc.RootElement()->FirstChildElement("two");
  1294. two->InsertFirstChild(subtree);
  1295. XMLPrinter printer1(0, true);
  1296. doc.Accept(&printer1);
  1297. XMLTest("Move node from within <one> to <two>", xmlInsideTwo, printer1.CStr());
  1298. doc.Parse(xml);
  1299. subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
  1300. two = doc.RootElement()->FirstChildElement("two");
  1301. doc.RootElement()->InsertAfterChild(two, subtree);
  1302. XMLPrinter printer2(0, true);
  1303. doc.Accept(&printer2);
  1304. XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer2.CStr(), false);
  1305. doc.Parse(xml);
  1306. XMLNode* one = doc.RootElement()->FirstChildElement("one");
  1307. subtree = one->FirstChildElement("subtree");
  1308. doc.RootElement()->InsertAfterChild(one, subtree);
  1309. XMLPrinter printer3(0, true);
  1310. doc.Accept(&printer3);
  1311. XMLTest("Move node from within <one> after <one>", xmlAfterOne, printer3.CStr(), false);
  1312. doc.Parse(xml);
  1313. subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
  1314. two = doc.RootElement()->FirstChildElement("two");
  1315. doc.RootElement()->InsertEndChild(subtree);
  1316. XMLPrinter printer4(0, true);
  1317. doc.Accept(&printer4);
  1318. XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer4.CStr(), false);
  1319. }
  1320. {
  1321. const char* xml = "<svg width = \"128\" height = \"128\">"
  1322. " <text> </text>"
  1323. "</svg>";
  1324. XMLDocument doc;
  1325. doc.Parse(xml);
  1326. doc.Print();
  1327. }
  1328. {
  1329. // Test that it doesn't crash.
  1330. const char* xml = "<?xml version=\"1.0\"?><root><sample><field0><1</field0><field1>2</field1></sample></root>";
  1331. XMLDocument doc;
  1332. doc.Parse(xml);
  1333. doc.PrintError();
  1334. }
  1335. #if 1
  1336. // the question being explored is what kind of print to use:
  1337. // https://github.com/leethomason/tinyxml2/issues/63
  1338. {
  1339. //const char* xml = "<element attrA='123456789.123456789' attrB='1.001e9' attrC='1.0e-10' attrD='1001000000.000000' attrE='0.1234567890123456789'/>";
  1340. const char* xml = "<element/>";
  1341. XMLDocument doc;
  1342. doc.Parse( xml );
  1343. doc.FirstChildElement()->SetAttribute( "attrA-f64", 123456789.123456789 );
  1344. doc.FirstChildElement()->SetAttribute( "attrB-f64", 1.001e9 );
  1345. doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e9 );
  1346. doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e20 );
  1347. doc.FirstChildElement()->SetAttribute( "attrD-f64", 1.0e-10 );
  1348. doc.FirstChildElement()->SetAttribute( "attrD-f64", 0.123456789 );
  1349. doc.FirstChildElement()->SetAttribute( "attrA-f32", 123456789.123456789f );
  1350. doc.FirstChildElement()->SetAttribute( "attrB-f32", 1.001e9f );
  1351. doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e9f );
  1352. doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e20f );
  1353. doc.FirstChildElement()->SetAttribute( "attrD-f32", 1.0e-10f );
  1354. doc.FirstChildElement()->SetAttribute( "attrD-f32", 0.123456789f );
  1355. doc.Print();
  1356. /* The result of this test is platform, compiler, and library version dependent. :("
  1357. XMLPrinter printer;
  1358. doc.Print( &printer );
  1359. XMLTest( "Float and double formatting.",
  1360. "<element attrA-f64=\"123456789.12345679\" attrB-f64=\"1001000000\" attrC-f64=\"1e+20\" attrD-f64=\"0.123456789\" attrA-f32=\"1.2345679e+08\" attrB-f32=\"1.001e+09\" attrC-f32=\"1e+20\" attrD-f32=\"0.12345679\"/>\n",
  1361. printer.CStr(),
  1362. true );
  1363. */
  1364. }
  1365. #endif
  1366. {
  1367. // Issue #184
  1368. // If it doesn't assert, it passes. Caused by objects
  1369. // getting created during parsing which are then
  1370. // inaccessible in the memory pools.
  1371. {
  1372. XMLDocument doc;
  1373. doc.Parse("<?xml version=\"1.0\" encoding=\"UTF-8\"?><test>");
  1374. }
  1375. {
  1376. XMLDocument doc;
  1377. doc.Parse("<?xml version=\"1.0\" encoding=\"UTF-8\"?><test>");
  1378. doc.Clear();
  1379. }
  1380. }
  1381. {
  1382. // If this doesn't assert in DEBUG, all is well.
  1383. tinyxml2::XMLDocument doc;
  1384. tinyxml2::XMLElement *pRoot = doc.NewElement("Root");
  1385. doc.DeleteNode(pRoot);
  1386. }
  1387. {
  1388. // Should not assert in DEBUG
  1389. XMLPrinter printer;
  1390. }
  1391. {
  1392. // Issue 291. Should not crash
  1393. const char* xml = "&#0</a>";
  1394. XMLDocument doc;
  1395. doc.Parse( xml );
  1396. XMLPrinter printer;
  1397. doc.Print( &printer );
  1398. }
  1399. {
  1400. // Issue 299. Can print elements that are not linked in.
  1401. // Will crash if issue not fixed.
  1402. XMLDocument doc;
  1403. XMLElement* newElement = doc.NewElement( "printme" );
  1404. XMLPrinter printer;
  1405. newElement->Accept( &printer );
  1406. // Delete the node to avoid possible memory leak report in debug output
  1407. doc.DeleteNode( newElement );
  1408. }
  1409. {
  1410. // Issue 302. Clear errors from LoadFile/SaveFile
  1411. XMLDocument doc;
  1412. XMLTest( "Issue 302. Should be no error initially", "XML_SUCCESS", doc.ErrorName() );
  1413. doc.SaveFile( "./no/such/path/pretty.xml" );
  1414. XMLTest( "Issue 302. Fail to save", "XML_ERROR_FILE_COULD_NOT_BE_OPENED", doc.ErrorName() );
  1415. doc.SaveFile( "./resources/out/compact.xml", true );
  1416. XMLTest( "Issue 302. Subsequent success in saving", "XML_SUCCESS", doc.ErrorName() );
  1417. }
  1418. {
  1419. // If a document fails to load then subsequent
  1420. // successful loads should clear the error
  1421. XMLDocument doc;
  1422. XMLTest( "Should be no error initially", false, doc.Error() );
  1423. doc.LoadFile( "resources/no-such-file.xml" );
  1424. XMLTest( "No such file - should fail", true, doc.Error() );
  1425. doc.LoadFile( "resources/dream.xml" );
  1426. XMLTest( "Error should be cleared", false, doc.Error() );
  1427. }
  1428. {
  1429. // Check that declarations are allowed only at beginning of document
  1430. const char* xml0 = "<?xml version=\"1.0\" ?>"
  1431. " <!-- xml version=\"1.1\" -->"
  1432. "<first />";
  1433. const char* xml1 = "<?xml version=\"1.0\" ?>"
  1434. "<?xml-stylesheet type=\"text/xsl\" href=\"Anything.xsl\"?>"
  1435. "<first />";
  1436. const char* xml2 = "<first />"
  1437. "<?xml version=\"1.0\" ?>";
  1438. const char* xml3 = "<first></first>"
  1439. "<?xml version=\"1.0\" ?>";
  1440. const char* xml4 = "<first><?xml version=\"1.0\" ?></first>";
  1441. XMLDocument doc;
  1442. doc.Parse(xml0);
  1443. XMLTest("Test that the code changes do not affect normal parsing", doc.Error(), false);
  1444. doc.Parse(xml1);
  1445. XMLTest("Test that the second declaration is allowed", doc.Error(), false);
  1446. doc.Parse(xml2);
  1447. XMLTest("Test that declaration after a child is not allowed", doc.ErrorID(), XML_ERROR_PARSING_DECLARATION);
  1448. doc.Parse(xml3);
  1449. XMLTest("Test that declaration after a child is not allowed", doc.ErrorID(), XML_ERROR_PARSING_DECLARATION);
  1450. doc.Parse(xml4);
  1451. XMLTest("Test that declaration inside a child is not allowed", doc.ErrorID(), XML_ERROR_PARSING_DECLARATION);
  1452. }
  1453. {
  1454. // No matter - before or after successfully parsing a text -
  1455. // calling XMLDocument::Value() causes an assert in debug.
  1456. const char* validXml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
  1457. "<first />"
  1458. "<second />";
  1459. XMLDocument* doc = new XMLDocument();
  1460. XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
  1461. doc->Parse( validXml );
  1462. XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
  1463. delete doc;
  1464. }
  1465. {
  1466. XMLDocument doc;
  1467. for( int i = 0; i < XML_ERROR_COUNT; i++ ) {
  1468. doc.SetError( (XMLError)i, 0, 0, 0 );
  1469. doc.ErrorName();
  1470. }
  1471. }
  1472. {
  1473. // Evil memory leaks.
  1474. // If an XMLElement (etc) is allocated via NewElement() (etc.)
  1475. // and NOT added to the XMLDocument, what happens?
  1476. //
  1477. // Previously (buggy):
  1478. // The memory would be free'd when the XMLDocument is
  1479. // destructed. But the destructor wasn't called, so that
  1480. // memory allocated by the XMLElement would not be free'd.
  1481. // In practice this meant strings allocated by the XMLElement
  1482. // would leak. An edge case, but annoying.
  1483. // Now:
  1484. // The destructor is called. But the list of unlinked nodes
  1485. // has to be tracked. This has a minor performance impact
  1486. // that can become significant if you have a lot. (But why
  1487. // would you do that?)
  1488. // The only way to see this bug is in a leak tracker. This
  1489. // is compiled in by default on Windows Debug.
  1490. {
  1491. XMLDocument doc;
  1492. doc.NewElement("LEAK 1");
  1493. }
  1494. {
  1495. XMLDocument doc;
  1496. XMLElement* ele = doc.NewElement("LEAK 2");
  1497. doc.DeleteNode(ele);
  1498. }
  1499. }
  1500. {
  1501. // Crashing reported via email.
  1502. const char* xml =
  1503. "<playlist id='playlist1'>"
  1504. "<property name='track_name'>voice</property>"
  1505. "<property name='audio_track'>1</property>"
  1506. "<entry out = '604' producer = '4_playlist1' in = '0' />"
  1507. "<blank length = '1' />"
  1508. "<entry out = '1625' producer = '3_playlist' in = '0' />"
  1509. "<blank length = '2' />"
  1510. "<entry out = '946' producer = '2_playlist1' in = '0' />"
  1511. "<blank length = '1' />"
  1512. "<entry out = '128' producer = '1_playlist1' in = '0' />"
  1513. "</playlist>";
  1514. // It's not a good idea to delete elements as you walk the
  1515. // list. I'm not sure this technically should work; but it's
  1516. // an interesting test case.
  1517. XMLDocument doc;
  1518. XMLError err = doc.Parse(xml);
  1519. XMLTest("Crash bug parsing", err, XML_SUCCESS);
  1520. XMLElement* playlist = doc.FirstChildElement("playlist");
  1521. XMLTest("Crash bug parsing", true, playlist != 0);
  1522. tinyxml2::XMLElement* entry = playlist->FirstChildElement("entry");
  1523. XMLTest("Crash bug parsing", true, entry != 0);
  1524. while (entry) {
  1525. tinyxml2::XMLElement* todelete = entry;
  1526. entry = entry->NextSiblingElement("entry");
  1527. playlist->DeleteChild(todelete);
  1528. };
  1529. tinyxml2::XMLElement* blank = playlist->FirstChildElement("blank");
  1530. while (blank) {
  1531. tinyxml2::XMLElement* todelete = blank;
  1532. blank = blank->NextSiblingElement("blank");
  1533. playlist->DeleteChild(todelete);
  1534. };
  1535. tinyxml2::XMLPrinter printer;
  1536. playlist->Accept(&printer);
  1537. printf("%s\n", printer.CStr());
  1538. // No test; it only need to not crash.
  1539. // Still, wrap it up with a sanity check
  1540. int nProperty = 0;
  1541. for (const XMLElement* p = playlist->FirstChildElement("property"); p; p = p->NextSiblingElement("property")) {
  1542. nProperty++;
  1543. }
  1544. XMLTest("Crash bug parsing", nProperty, 2);
  1545. }
  1546. // ----------- Line Number Tracking --------------
  1547. {
  1548. struct TestUtil: XMLVisitor
  1549. {
  1550. void TestParseError(const char *testString, const char *docStr, XMLError expected_error, int expectedLine)
  1551. {
  1552. XMLDocument doc;
  1553. XMLError err = doc.Parse(docStr);
  1554. XMLTest(testString, true, doc.Error());
  1555. XMLTest(testString, expected_error, err);
  1556. XMLTest(testString, expectedLine, doc.GetErrorLineNum());
  1557. };
  1558. void TestStringLines(const char *testString, const char *docStr, const char *expectedLines)
  1559. {
  1560. XMLDocument doc;
  1561. doc.Parse(docStr);
  1562. XMLTest(testString, false, doc.Error());
  1563. TestDocLines(testString, doc, expectedLines);
  1564. }
  1565. void TestFileLines(const char *testString, const char *file_name, const char *expectedLines)
  1566. {
  1567. XMLDocument doc;
  1568. doc.LoadFile(file_name);
  1569. XMLTest(testString, false, doc.Error());
  1570. TestDocLines(testString, doc, expectedLines);
  1571. }
  1572. private:
  1573. DynArray<char, 10> str;
  1574. void Push(char type, int lineNum)
  1575. {
  1576. str.Push(type);
  1577. str.Push(char('0' + (lineNum / 10)));
  1578. str.Push(char('0' + (lineNum % 10)));
  1579. }
  1580. bool VisitEnter(const XMLDocument& doc)
  1581. {
  1582. Push('D', doc.GetLineNum());
  1583. return true;
  1584. }
  1585. bool VisitEnter(const XMLElement& element, const XMLAttribute* firstAttribute)
  1586. {
  1587. Push('E', element.GetLineNum());
  1588. for (const XMLAttribute *attr = firstAttribute; attr != 0; attr = attr->Next())
  1589. Push('A', attr->GetLineNum());
  1590. return true;
  1591. }
  1592. bool Visit(const XMLDeclaration& declaration)
  1593. {
  1594. Push('L', declaration.GetLineNum());
  1595. return true;
  1596. }
  1597. bool Visit(const XMLText& text)
  1598. {
  1599. Push('T', text.GetLineNum());
  1600. return true;
  1601. }
  1602. bool Visit(const XMLComment& comment)
  1603. {
  1604. Push('C', comment.GetLineNum());
  1605. return true;
  1606. }
  1607. bool Visit(const XMLUnknown& unknown)
  1608. {
  1609. Push('U', unknown.GetLineNum());
  1610. return true;
  1611. }
  1612. void TestDocLines(const char *testString, XMLDocument &doc, const char *expectedLines)
  1613. {
  1614. str.Clear();
  1615. doc.Accept(this);
  1616. str.Push(0);
  1617. XMLTest(testString, expectedLines, str.Mem());
  1618. }
  1619. } tester;
  1620. tester.TestParseError("ErrorLine-Parsing", "\n<root>\n foo \n<unclosed/>", XML_ERROR_PARSING, 2);
  1621. tester.TestParseError("ErrorLine-Declaration", "<root>\n<?xml version=\"1.0\"?>", XML_ERROR_PARSING_DECLARATION, 2);
  1622. tester.TestParseError("ErrorLine-Mismatch", "\n<root>\n</mismatch>", XML_ERROR_MISMATCHED_ELEMENT, 2);
  1623. tester.TestParseError("ErrorLine-CData", "\n<root><![CDATA[ \n foo bar \n", XML_ERROR_PARSING_CDATA, 2);
  1624. tester.TestParseError("ErrorLine-Text", "\n<root>\n foo bar \n", XML_ERROR_PARSING_TEXT, 3);
  1625. tester.TestParseError("ErrorLine-Comment", "\n<root>\n<!-- >\n", XML_ERROR_PARSING_COMMENT, 3);
  1626. tester.TestParseError("ErrorLine-Declaration", "\n<root>\n<? >\n", XML_ERROR_PARSING_DECLARATION, 3);
  1627. tester.TestParseError("ErrorLine-Unknown", "\n<root>\n<! \n", XML_ERROR_PARSING_UNKNOWN, 3);
  1628. tester.TestParseError("ErrorLine-Element", "\n<root>\n<unclosed \n", XML_ERROR_PARSING_ELEMENT, 3);
  1629. tester.TestParseError("ErrorLine-Attribute", "\n<root>\n<unclosed \n att\n", XML_ERROR_PARSING_ATTRIBUTE, 4);
  1630. tester.TestParseError("ErrorLine-ElementClose", "\n<root>\n<unclosed \n/unexpected", XML_ERROR_PARSING_ELEMENT, 3);
  1631. tester.TestStringLines(
  1632. "LineNumbers-String",
  1633. "<?xml version=\"1.0\"?>\n" // 1 Doc, DecL
  1634. "<root a='b' \n" // 2 Element Attribute
  1635. "c='d'> d <blah/> \n" // 3 Attribute Text Element
  1636. "newline in text \n" // 4 Text
  1637. "and second <zxcv/><![CDATA[\n" // 5 Element Text
  1638. " cdata test ]]><!-- comment -->\n" // 6 Comment
  1639. "<! unknown></root>", // 7 Unknown
  1640. "D01L01E02A02A03T03E03T04E05T05C06U07");
  1641. tester.TestStringLines(
  1642. "LineNumbers-CRLF",
  1643. "\r\n" // 1 Doc (arguably should be line 2)
  1644. "<?xml version=\"1.0\"?>\n" // 2 DecL
  1645. "<root>\r\n" // 3 Element
  1646. "\n" // 4
  1647. "text contining new line \n" // 5 Text
  1648. " and also containing crlf \r\n" // 6
  1649. "<sub><![CDATA[\n" // 7 Element Text
  1650. "cdata containing new line \n" // 8
  1651. " and also containing cflr\r\n" // 9
  1652. "]]></sub><sub2/></root>", // 10 Element
  1653. "D01L02E03T05E07T07E10");
  1654. tester.TestFileLines(
  1655. "LineNumbers-File",
  1656. "resources/utf8test.xml",
  1657. "D01L01E02E03A03A03T03E04A04A04T04E05A05A05T05E06A06A06T06E07A07A07T07E08A08A08T08E09T09E10T10");
  1658. }
  1659. // ----------- Performance tracking --------------
  1660. {
  1661. #if defined( _MSC_VER )
  1662. __int64 start, end, freq;
  1663. QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
  1664. #endif
  1665. FILE* perfFP = fopen("resources/dream.xml", "r");
  1666. fseek(perfFP, 0, SEEK_END);
  1667. long size = ftell(perfFP);
  1668. fseek(perfFP, 0, SEEK_SET);
  1669. char* mem = new char[size + 1];
  1670. fread(mem, size, 1, perfFP);
  1671. fclose(perfFP);
  1672. mem[size] = 0;
  1673. #if defined( _MSC_VER )
  1674. QueryPerformanceCounter((LARGE_INTEGER*)&start);
  1675. #else
  1676. clock_t cstart = clock();
  1677. #endif
  1678. static const int COUNT = 10;
  1679. for (int i = 0; i < COUNT; ++i) {
  1680. XMLDocument doc;
  1681. doc.Parse(mem);
  1682. }
  1683. #if defined( _MSC_VER )
  1684. QueryPerformanceCounter((LARGE_INTEGER*)&end);
  1685. #else
  1686. clock_t cend = clock();
  1687. #endif
  1688. delete[] mem;
  1689. static const char* note =
  1690. #ifdef DEBUG
  1691. "DEBUG";
  1692. #else
  1693. "Release";
  1694. #endif
  1695. #if defined( _MSC_VER )
  1696. printf("\nParsing %s of dream.xml: %.3f milli-seconds\n", note, 1000.0 * (double)(end - start) / ((double)freq * (double)COUNT));
  1697. #else
  1698. printf("\nParsing %s of dream.xml: %.3f milli-seconds\n", note, (double)(cend - cstart) / (double)COUNT);
  1699. #endif
  1700. }
  1701. #if defined( _MSC_VER ) && defined( DEBUG )
  1702. _CrtMemCheckpoint( &endMemState );
  1703. _CrtMemState diffMemState;
  1704. _CrtMemDifference( &diffMemState, &startMemState, &endMemState );
  1705. _CrtMemDumpStatistics( &diffMemState );
  1706. {
  1707. int leaksBeforeExit = _CrtDumpMemoryLeaks();
  1708. XMLTest( "No leaks before exit?", FALSE, leaksBeforeExit );
  1709. }
  1710. #endif
  1711. printf ("\nPass %d, Fail %d\n", gPass, gFail);
  1712. return gFail;
  1713. }