tinyxml2.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792
  1. #include "tinyxml2.h"
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include <stdio.h>
  5. #include <ctype.h>
  6. using namespace tinyxml2;
  7. static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
  8. static const char LF = LINE_FEED;
  9. static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
  10. static const char CR = CARRIAGE_RETURN;
  11. static const char SINGLE_QUOTE = '\'';
  12. static const char DOUBLE_QUOTE = '\"';
  13. struct Entity {
  14. const char* pattern;
  15. int length;
  16. char value;
  17. };
  18. static const int NUM_ENTITIES = 5;
  19. static const Entity entities[NUM_ENTITIES] =
  20. {
  21. { "quot", 4, DOUBLE_QUOTE },
  22. { "amp", 3, '&' },
  23. { "apos", 4, SINGLE_QUOTE },
  24. { "lt", 2, '<' },
  25. { "gt", 2, '>' }
  26. };
  27. const char* StrPair::GetStr()
  28. {
  29. if ( flags & NEEDS_FLUSH ) {
  30. *end = 0;
  31. flags ^= NEEDS_FLUSH;
  32. if ( flags ) {
  33. char* p = start;
  34. char* q = start;
  35. while( p < end ) {
  36. if ( (flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
  37. // CR-LF pair becomes LF
  38. // CR alone becomes LF
  39. // LF-CR becomes LF
  40. if ( *(p+1) == LF ) {
  41. p += 2;
  42. }
  43. else {
  44. ++p;
  45. }
  46. *q = LF;
  47. }
  48. else if ( (flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
  49. if ( *(p+1) == CR ) {
  50. p += 2;
  51. }
  52. else {
  53. ++p;
  54. }
  55. *q = LF;
  56. }
  57. else if ( (flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
  58. int i=0;
  59. for( i=0; i<NUM_ENTITIES; ++i ) {
  60. if ( strncmp( p+1, entities[i].pattern, entities[i].length ) == 0
  61. && *(p+entities[i].length+1) == ';' )
  62. {
  63. // Found an entity convert;
  64. *q = entities[i].value;
  65. ++q;
  66. p += entities[i].length + 2;
  67. break;
  68. }
  69. }
  70. if ( i == NUM_ENTITIES ) {
  71. // fixme: treat as error?
  72. ++p;
  73. ++q;
  74. }
  75. }
  76. else {
  77. *q = *p;
  78. ++p;
  79. ++q;
  80. }
  81. }
  82. *q = 0;
  83. }
  84. flags = 0;
  85. }
  86. return start;
  87. }
  88. /*
  89. const char* StringPool::Intern( const char* str )
  90. {
  91. // Treat the array as a linear, inplace hash table.
  92. // Nothing can get deleted, so that's handy.
  93. if ( size > pool.Size()*3/4 ) {
  94. DynArray< const char*, 20 > store;
  95. for( int i=0; i<pool.Size(); ++i ) {
  96. if ( pool[i] != 0 ) {
  97. store.Push( pool[i] );
  98. }
  99. }
  100. int newSize = pool.Size() * 2;
  101. pool.PopArr( pool.Size() );
  102. const char** mem = pool.PushArr( newSize );
  103. memset( (void*)mem, 0, sizeof(char)*newSize );
  104. while ( !store.Empty() ) {
  105. Intern( store.Pop() );
  106. }
  107. }
  108. }
  109. */
  110. // --------- XMLBase ----------- //
  111. // fixme: should take in the entity/newline flags as param
  112. char* XMLBase::ParseText( char* p, StrPair* pair, const char* endTag, int strFlags )
  113. {
  114. TIXMLASSERT( endTag && *endTag );
  115. char* start = p;
  116. char endChar = *endTag;
  117. int length = strlen( endTag );
  118. // Inner loop of text parsing.
  119. while ( *p ) {
  120. if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
  121. pair->Set( start, p, strFlags );
  122. return p + length;
  123. }
  124. ++p;
  125. }
  126. return p;
  127. }
  128. char* XMLBase::ParseName( char* p, StrPair* pair )
  129. {
  130. char* start = p;
  131. start = p;
  132. if ( !start || !(*start) ) {
  133. return 0;
  134. }
  135. if ( !IsAlpha( *p ) ) {
  136. return 0;
  137. }
  138. while( *p && (
  139. IsAlphaNum( (unsigned char) *p )
  140. || *p == '_'
  141. || *p == '-'
  142. || *p == '.'
  143. || *p == ':' ))
  144. {
  145. ++p;
  146. }
  147. if ( p > start ) {
  148. pair->Set( start, p, 0 );
  149. return p;
  150. }
  151. return 0;
  152. }
  153. char* XMLBase::Identify( XMLDocument* document, char* p, XMLNode** node )
  154. {
  155. XMLNode* returnNode = 0;
  156. char* start = p;
  157. p = XMLNode::SkipWhiteSpace( p );
  158. if( !p || !*p )
  159. {
  160. return 0;
  161. }
  162. // What is this thing?
  163. // - Elements start with a letter or underscore, but xml is reserved.
  164. // - Comments: <!--
  165. // - Decleration: <?xml
  166. // - Everthing else is unknown to tinyxml.
  167. //
  168. static const char* xmlHeader = { "<?xml" };
  169. static const char* commentHeader = { "<!--" };
  170. static const char* dtdHeader = { "<!" };
  171. static const char* cdataHeader = { "<![CDATA[" };
  172. static const char* elementHeader = { "<" }; // and a header for everything else; check last.
  173. static const int xmlHeaderLen = 5;
  174. static const int commentHeaderLen = 4;
  175. static const int dtdHeaderLen = 2;
  176. static const int cdataHeaderLen = 9;
  177. static const int elementHeaderLen = 1;
  178. if ( StringEqual( p, commentHeader, commentHeaderLen ) ) {
  179. returnNode = new XMLComment( document );
  180. p += commentHeaderLen;
  181. }
  182. else if ( StringEqual( p, elementHeader, elementHeaderLen ) ) {
  183. returnNode = new XMLElement( document );
  184. p += elementHeaderLen;
  185. }
  186. // fixme: better text detection
  187. else if ( (*p != '<') && IsAlphaNum( *p ) ) {
  188. // fixme: this is filtering out empty text...should it?
  189. returnNode = new XMLText( document );
  190. p = start; // Back it up, all the text counts.
  191. }
  192. else {
  193. TIXMLASSERT( 0 );
  194. }
  195. *node = returnNode;
  196. return p;
  197. }
  198. // --------- XMLNode ----------- //
  199. XMLNode::XMLNode( XMLDocument* doc ) :
  200. document( doc ),
  201. parent( 0 ),
  202. isTextParent( false ),
  203. firstChild( 0 ), lastChild( 0 ),
  204. prev( 0 ), next( 0 )
  205. {
  206. }
  207. XMLNode::~XMLNode()
  208. {
  209. ClearChildren();
  210. if ( parent ) {
  211. parent->Unlink( this );
  212. }
  213. }
  214. void XMLNode::ClearChildren()
  215. {
  216. while( firstChild ) {
  217. XMLNode* node = firstChild;
  218. Unlink( node );
  219. delete node;
  220. }
  221. firstChild = lastChild = 0;
  222. }
  223. void XMLNode::Unlink( XMLNode* child )
  224. {
  225. TIXMLASSERT( child->parent == this );
  226. if ( child == firstChild )
  227. firstChild = firstChild->next;
  228. if ( child == lastChild )
  229. lastChild = lastChild->prev;
  230. if ( child->prev ) {
  231. child->prev->next = child->next;
  232. }
  233. if ( child->next ) {
  234. child->next->prev = child->prev;
  235. }
  236. child->parent = 0;
  237. }
  238. XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
  239. {
  240. if ( lastChild ) {
  241. TIXMLASSERT( firstChild );
  242. TIXMLASSERT( lastChild->next == 0 );
  243. lastChild->next = addThis;
  244. addThis->prev = lastChild;
  245. lastChild = addThis;
  246. addThis->parent = this;
  247. addThis->next = 0;
  248. }
  249. else {
  250. TIXMLASSERT( firstChild == 0 );
  251. firstChild = lastChild = addThis;
  252. addThis->parent = this;
  253. addThis->prev = 0;
  254. addThis->next = 0;
  255. }
  256. if ( addThis->ToText() ) {
  257. SetTextParent();
  258. }
  259. return addThis;
  260. }
  261. XMLElement* XMLNode::FirstChildElement( const char* value )
  262. {
  263. for( XMLNode* node=firstChild; node; node=node->next ) {
  264. XMLElement* element = node->ToElement();
  265. if ( element ) {
  266. if ( !value || StringEqual( element->Name(), value ) ) {
  267. return element;
  268. }
  269. }
  270. }
  271. return 0;
  272. }
  273. void XMLNode::Print( XMLStreamer* streamer )
  274. {
  275. for( XMLNode* node = firstChild; node; node=node->next ) {
  276. node->Print( streamer );
  277. }
  278. }
  279. char* XMLNode::ParseDeep( char* p )
  280. {
  281. while( p && *p ) {
  282. XMLNode* node = 0;
  283. p = Identify( document, p, &node );
  284. if ( p && node ) {
  285. p = node->ParseDeep( p );
  286. // FIXME: is it the correct closing element?
  287. if ( node->IsClosingElement() ) {
  288. delete node;
  289. return p;
  290. }
  291. this->InsertEndChild( node );
  292. }
  293. }
  294. return 0;
  295. }
  296. // --------- XMLText ---------- //
  297. char* XMLText::ParseDeep( char* p )
  298. {
  299. p = ParseText( p, &value, "<", StrPair::TEXT_ELEMENT );
  300. // consumes the end tag.
  301. if ( p && *p ) {
  302. return p-1;
  303. }
  304. return 0;
  305. }
  306. void XMLText::Print( XMLStreamer* streamer )
  307. {
  308. const char* v = value.GetStr();
  309. streamer->PushText( v );
  310. }
  311. // --------- XMLComment ---------- //
  312. XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
  313. {
  314. }
  315. XMLComment::~XMLComment()
  316. {
  317. //printf( "~XMLComment\n" );
  318. }
  319. void XMLComment::Print( XMLStreamer* streamer )
  320. {
  321. // XMLNode::Print( fp, depth );
  322. // fprintf( fp, "<!--%s-->\n", value.GetStr() );
  323. streamer->PushComment( value.GetStr() );
  324. }
  325. char* XMLComment::ParseDeep( char* p )
  326. {
  327. // Comment parses as text.
  328. return ParseText( p, &value, "-->", StrPair::COMMENT );
  329. }
  330. // --------- XMLAttribute ---------- //
  331. char* XMLAttribute::ParseDeep( char* p )
  332. {
  333. p = ParseText( p, &name, "=", StrPair::ATTRIBUTE_NAME );
  334. if ( !p || !*p ) return 0;
  335. char endTag[2] = { *p, 0 };
  336. ++p;
  337. p = ParseText( p, &value, endTag, StrPair::ATTRIBUTE_VALUE );
  338. if ( value.Empty() ) return 0;
  339. return p;
  340. }
  341. void XMLAttribute::Print( XMLStreamer* streamer )
  342. {
  343. // fixme: sort out single vs. double quote
  344. //fprintf( cfile, "%s=\"%s\"", name.GetStr(), value.GetStr() );
  345. streamer->PushAttribute( name.GetStr(), value.GetStr() );
  346. }
  347. // --------- XMLElement ---------- //
  348. XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
  349. closing( false ),
  350. rootAttribute( 0 ),
  351. lastAttribute( 0 )
  352. {
  353. }
  354. XMLElement::~XMLElement()
  355. {
  356. //printf( "~XMLElemen %x\n",this );
  357. XMLAttribute* attribute = rootAttribute;
  358. while( attribute ) {
  359. XMLAttribute* next = attribute->next;
  360. delete attribute;
  361. attribute = next;
  362. }
  363. }
  364. char* XMLElement::ParseAttributes( char* p, bool* closedElement )
  365. {
  366. const char* start = p;
  367. *closedElement = false;
  368. // Read the attributes.
  369. while( p ) {
  370. p = SkipWhiteSpace( p );
  371. if ( !p || !(*p) ) {
  372. document->SetError( XMLDocument::ERROR_PARSING_ELEMENT, start, name.GetStr() );
  373. return 0;
  374. }
  375. // attribute.
  376. if ( IsAlpha( *p ) ) {
  377. XMLAttribute* attrib = new XMLAttribute( this );
  378. p = attrib->ParseDeep( p );
  379. if ( !p ) {
  380. delete attrib;
  381. document->SetError( XMLDocument::ERROR_PARSING_ATTRIBUTE, start, p );
  382. return 0;
  383. }
  384. if ( rootAttribute ) {
  385. TIXMLASSERT( lastAttribute );
  386. lastAttribute->next = attrib;
  387. lastAttribute = attrib;
  388. }
  389. else {
  390. rootAttribute = lastAttribute = attrib;
  391. }
  392. }
  393. // end of the tag
  394. else if ( *p == '/' && *(p+1) == '>' ) {
  395. if ( closing ) {
  396. document->SetError( XMLDocument::ERROR_PARSING_ELEMENT, start, p );
  397. return 0;
  398. }
  399. *closedElement = true;
  400. return p+2; // done; sealed element.
  401. }
  402. // end of the tag
  403. else if ( *p == '>' ) {
  404. ++p;
  405. break;
  406. }
  407. else {
  408. document->SetError( XMLDocument::ERROR_PARSING_ELEMENT, start, p );
  409. return 0;
  410. }
  411. }
  412. return p;
  413. }
  414. //
  415. // <ele></ele>
  416. // <ele>foo<b>bar</b></ele>
  417. //
  418. char* XMLElement::ParseDeep( char* p )
  419. {
  420. // Read the element name.
  421. p = SkipWhiteSpace( p );
  422. if ( !p ) return 0;
  423. const char* start = p;
  424. // The closing element is the </element> form. It is
  425. // parsed just like a regular element then deleted from
  426. // the DOM.
  427. if ( *p == '/' ) {
  428. closing = true;
  429. ++p;
  430. }
  431. p = ParseName( p, &name );
  432. if ( name.Empty() ) return 0;
  433. bool elementClosed=false;
  434. p = ParseAttributes( p, &elementClosed );
  435. if ( !p || !*p || elementClosed || closing )
  436. return p;
  437. p = XMLNode::ParseDeep( p );
  438. return p;
  439. }
  440. void XMLElement::Print( XMLStreamer* streamer )
  441. {
  442. //if ( !parent || !parent->IsTextParent() ) {
  443. // PrintSpace( cfile, depth );
  444. //}
  445. //fprintf( cfile, "<%s", Name() );
  446. streamer->OpenElement( Name(), IsTextParent() );
  447. for( XMLAttribute* attrib=rootAttribute; attrib; attrib=attrib->next ) {
  448. //fprintf( cfile, " " );
  449. attrib->Print( streamer );
  450. }
  451. for( XMLNode* node=firstChild; node; node=node->next ) {
  452. node->Print( streamer );
  453. }
  454. streamer->CloseElement();
  455. }
  456. // --------- XMLDocument ----------- //
  457. XMLDocument::XMLDocument() :
  458. XMLNode( 0 ),
  459. charBuffer( 0 )
  460. {
  461. document = this; // avoid warning about 'this' in initializer list
  462. }
  463. XMLDocument::~XMLDocument()
  464. {
  465. delete [] charBuffer;
  466. }
  467. void XMLDocument::InitDocument()
  468. {
  469. errorID = NO_ERROR;
  470. errorStr1 = 0;
  471. errorStr2 = 0;
  472. delete [] charBuffer;
  473. charBuffer = 0;
  474. }
  475. XMLElement* XMLDocument::NewElement( const char* name )
  476. {
  477. XMLElement* ele = new XMLElement( this );
  478. ele->SetName( name );
  479. return ele;
  480. }
  481. int XMLDocument::Parse( const char* p )
  482. {
  483. ClearChildren();
  484. InitDocument();
  485. if ( !p || !*p ) {
  486. return true; // correctly parse an empty string?
  487. }
  488. size_t len = strlen( p );
  489. charBuffer = new char[ len+1 ];
  490. memcpy( charBuffer, p, len+1 );
  491. XMLNode* node = 0;
  492. char* q = ParseDeep( charBuffer );
  493. return errorID;
  494. }
  495. void XMLDocument::Print( XMLStreamer* streamer )
  496. {
  497. XMLStreamer stdStreamer( stdout );
  498. if ( !streamer )
  499. streamer = &stdStreamer;
  500. for( XMLNode* node = firstChild; node; node=node->next ) {
  501. node->Print( streamer );
  502. }
  503. }
  504. void XMLDocument::SetError( int error, const char* str1, const char* str2 )
  505. {
  506. errorID = error;
  507. printf( "ERROR: id=%d '%s' '%s'\n", error, str1, str2 ); // fixme: remove
  508. errorStr1 = str1;
  509. errorStr2 = str2;
  510. }
  511. /*
  512. StringStack::StringStack()
  513. {
  514. nPositive = 0;
  515. mem.Push( 0 ); // start with null. makes later code simpler.
  516. }
  517. StringStack::~StringStack()
  518. {
  519. }
  520. void StringStack::Push( const char* str ) {
  521. int needed = strlen( str ) + 1;
  522. char* p = mem.PushArr( needed );
  523. strcpy( p, str );
  524. if ( needed > 1 )
  525. nPositive++;
  526. }
  527. const char* StringStack::Pop() {
  528. TIXMLASSERT( mem.Size() > 1 );
  529. const char* p = mem.Mem() + mem.Size() - 2; // end of final string.
  530. if ( *p ) {
  531. nPositive--;
  532. }
  533. while( *p ) { // stack starts with a null, don't need to check for 'mem'
  534. TIXMLASSERT( p > mem.Mem() );
  535. --p;
  536. }
  537. mem.PopArr( strlen(p)+1 );
  538. return p+1;
  539. }
  540. */
  541. XMLStreamer::XMLStreamer( FILE* file ) : fp( file ), depth( 0 ), elementJustOpened( false )
  542. {
  543. for( int i=0; i<ENTITY_RANGE; ++i ) {
  544. entityFlag[i] = false;
  545. }
  546. for( int i=0; i<NUM_ENTITIES; ++i ) {
  547. TIXMLASSERT( entities[i].value < ENTITY_RANGE );
  548. if ( entities[i].value < ENTITY_RANGE ) {
  549. entityFlag[ entities[i].value ] = true;
  550. }
  551. }
  552. }
  553. void XMLStreamer::PrintSpace( int depth )
  554. {
  555. for( int i=0; i<depth; ++i ) {
  556. fprintf( fp, " " );
  557. }
  558. }
  559. void XMLStreamer::PrintString( const char* p )
  560. {
  561. // Look for runs of bytes between entities to print.
  562. const char* q = p;
  563. while ( *q ) {
  564. if ( *q < ENTITY_RANGE ) {
  565. // Check for entities. If one is found, flush
  566. // the stream up until the entity, write the
  567. // entity, and keep looking.
  568. if ( entityFlag[*q] ) {
  569. while ( p < q ) {
  570. fputc( *p, fp );
  571. ++p;
  572. }
  573. for( int i=0; i<NUM_ENTITIES; ++i ) {
  574. if ( entities[i].value == *q ) {
  575. fprintf( fp, "&%s;", entities[i].pattern );
  576. break;
  577. }
  578. }
  579. ++p;
  580. }
  581. }
  582. ++q;
  583. }
  584. // Flush the remaining string. This will be the entire
  585. // string if an entity wasn't found.
  586. if ( q-p > 0 ) {
  587. fprintf( fp, "%s", p );
  588. }
  589. }
  590. void XMLStreamer::OpenElement( const char* name, bool textParent )
  591. {
  592. if ( elementJustOpened ) {
  593. SealElement();
  594. }
  595. if ( !TextOnStack() ) {
  596. PrintSpace( depth );
  597. }
  598. stack.Push( name );
  599. text.Push( textParent ? 'T' : 'e' );
  600. // fixme: can names have entities?
  601. fprintf( fp, "<%s", name );
  602. elementJustOpened = true;
  603. ++depth;
  604. }
  605. void XMLStreamer::PushAttribute( const char* name, const char* value )
  606. {
  607. TIXMLASSERT( elementJustOpened );
  608. fprintf( fp, " %s=\"", name );
  609. PrintString( value );
  610. fprintf( fp, "\"" );
  611. }
  612. void XMLStreamer::CloseElement()
  613. {
  614. --depth;
  615. const char* name = stack.Pop();
  616. bool wasText = TextOnStack();
  617. text.Pop();
  618. if ( elementJustOpened ) {
  619. fprintf( fp, "/>" );
  620. if ( !wasText ) {
  621. fprintf( fp, "\n" );
  622. }
  623. }
  624. else {
  625. if ( !wasText ) {
  626. PrintSpace( depth );
  627. }
  628. // fixme can names have entities?
  629. fprintf( fp, "</%s>", name );
  630. if ( !TextOnStack() ) {
  631. fprintf( fp, "\n" );
  632. }
  633. }
  634. elementJustOpened = false;
  635. }
  636. void XMLStreamer::SealElement()
  637. {
  638. elementJustOpened = false;
  639. fprintf( fp, ">" );
  640. if ( !TextOnStack() ) {
  641. fprintf( fp, "\n" );
  642. }
  643. }
  644. void XMLStreamer::PushText( const char* text )
  645. {
  646. if ( elementJustOpened ) {
  647. SealElement();
  648. }
  649. PrintString( text );
  650. }
  651. void XMLStreamer::PushComment( const char* comment )
  652. {
  653. if ( elementJustOpened ) {
  654. SealElement();
  655. }
  656. PrintSpace( depth );
  657. fprintf( fp, "<!--%s-->\n", comment );
  658. }