tinyxml2.cpp 15 KB

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