tinyxml2.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  1. #ifndef TINYXML2_INCLUDED
  2. #define TINYXML2_INCLUDED
  3. /*
  4. TODO
  5. - const and non-const versions of API
  6. - memory pool the class construction
  7. - attribute accessors
  8. - node navigation
  9. - handles
  10. - visit pattern - change streamer?
  11. - make constructors protected
  12. - hide copy constructor
  13. - hide = operator
  14. - #define to remove mem-pooling, and make thread safe
  15. - UTF8 support: isAlpha, etc.
  16. (No reason to ever cast to base)
  17. XMLBase -> Utility
  18. XMLNode
  19. Document
  20. Pooled
  21. Element
  22. Text
  23. */
  24. #include <limits.h>
  25. #include <ctype.h>
  26. #include <stdio.h>
  27. #include <memory.h>
  28. #if defined( _DEBUG ) || defined( DEBUG ) || defined (__DEBUG__)
  29. #ifndef DEBUG
  30. #define DEBUG
  31. #endif
  32. #endif
  33. #if defined(DEBUG)
  34. #if defined(_MSC_VER)
  35. #define TIXMLASSERT( x ) if ( !(x)) { _asm { int 3 } } //if ( !(x)) WinDebugBreak()
  36. #elif defined (ANDROID_NDK)
  37. #include <android/log.h>
  38. #define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); }
  39. #else
  40. #include <assert.h>
  41. #define TIXMLASSERT assert
  42. #endif
  43. #else
  44. #define TIXMLASSERT( x ) {}
  45. #endif
  46. namespace tinyxml2
  47. {
  48. class XMLDocument;
  49. class XMLElement;
  50. class XMLAttribute;
  51. class XMLComment;
  52. class XMLNode;
  53. class XMLText;
  54. class XMLStreamer;
  55. class StrPair
  56. {
  57. public:
  58. enum {
  59. NEEDS_ENTITY_PROCESSING = 0x01,
  60. NEEDS_NEWLINE_NORMALIZATION = 0x02,
  61. TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
  62. ATTRIBUTE_NAME = 0,
  63. ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
  64. COMMENT = NEEDS_NEWLINE_NORMALIZATION,
  65. };
  66. StrPair() : flags( 0 ), start( 0 ), end( 0 ) {}
  67. void Set( char* start, char* end, int flags ) {
  68. this->start = start; this->end = end; this->flags = flags | NEEDS_FLUSH;
  69. }
  70. const char* GetStr();
  71. bool Empty() const { return start == end; }
  72. void SetInternedStr( const char* str ) { this->start = (char*) str; this->end = 0; this->flags = 0; }
  73. private:
  74. enum {
  75. NEEDS_FLUSH = 0x100
  76. };
  77. // After parsing, if *end != 0, it can be set to zero.
  78. int flags;
  79. char* start;
  80. char* end;
  81. };
  82. template <class T, int INIT>
  83. class DynArray
  84. {
  85. public:
  86. DynArray< T, INIT >()
  87. {
  88. mem = pool;
  89. allocated = INIT;
  90. size = 0;
  91. }
  92. ~DynArray()
  93. {
  94. if ( mem != pool ) {
  95. delete mem;
  96. }
  97. }
  98. void Push( T t )
  99. {
  100. EnsureCapacity( size+1 );
  101. mem[size++] = t;
  102. }
  103. T* PushArr( int count )
  104. {
  105. EnsureCapacity( size+count );
  106. T* ret = &mem[size];
  107. size += count;
  108. return ret;
  109. }
  110. T Pop() {
  111. return mem[--size];
  112. }
  113. void PopArr( int count )
  114. {
  115. TIXMLASSERT( size >= count );
  116. size -= count;
  117. }
  118. bool Empty() const { return size == 0; }
  119. T& operator[](int i) { TIXMLASSERT( i>= 0 && i < size ); return mem[i]; }
  120. const T& operator[](int i) const { TIXMLASSERT( i>= 0 && i < size ); return mem[i]; }
  121. int Size() const { return size; }
  122. const T* Mem() const { return mem; }
  123. T* Mem() { return mem; }
  124. private:
  125. void EnsureCapacity( int cap ) {
  126. if ( cap > allocated ) {
  127. int newAllocated = cap * 2;
  128. T* newMem = new T[newAllocated];
  129. memcpy( newMem, mem, sizeof(T)*size ); // warning: not using constructors, only works for PODs
  130. if ( mem != pool ) delete [] mem;
  131. mem = newMem;
  132. allocated = newAllocated;
  133. }
  134. }
  135. T* mem;
  136. T pool[INIT];
  137. int allocated; // objects allocated
  138. int size; // number objects in use
  139. };
  140. class MemPool
  141. {
  142. public:
  143. MemPool() {}
  144. virtual ~MemPool() {}
  145. virtual int ItemSize() const = 0;
  146. virtual void* Alloc() = 0;
  147. virtual void Free( void* ) = 0;
  148. };
  149. template< int SIZE >
  150. class MemPoolT : public MemPool
  151. {
  152. public:
  153. MemPoolT() : root( 0 ), nAlloc( 0 ) {}
  154. ~MemPoolT() {
  155. // Delete the blocks.
  156. for( int i=0; i<blockPtrs.Size(); ++i ) {
  157. delete blockPtrs[i];
  158. }
  159. }
  160. virtual int ItemSize() const { return SIZE; }
  161. int NAlloc() const { return nAlloc; }
  162. virtual void* Alloc() {
  163. if ( !root ) {
  164. // Need a new block.
  165. Block* block = new Block();
  166. blockPtrs.Push( block );
  167. for( int i=0; i<COUNT-1; ++i ) {
  168. block->chunk[i].next = &block->chunk[i+1];
  169. }
  170. block->chunk[COUNT-1].next = 0;
  171. root = block->chunk;
  172. }
  173. void* result = root;
  174. root = root->next;
  175. ++nAlloc;
  176. return result;
  177. }
  178. virtual void Free( void* mem ) {
  179. if ( !mem ) return;
  180. --nAlloc;
  181. Chunk* chunk = (Chunk*)mem;
  182. memset( chunk, 0xfe, sizeof(Chunk) );
  183. chunk->next = root;
  184. root = chunk;
  185. }
  186. private:
  187. enum { COUNT = 1024/SIZE };
  188. union Chunk {
  189. Chunk* next;
  190. char mem[SIZE];
  191. };
  192. struct Block {
  193. Chunk chunk[COUNT];
  194. };
  195. DynArray< Block*, 10 > blockPtrs;
  196. Chunk* root;
  197. int nAlloc;
  198. };
  199. /*
  200. class StringStack
  201. {
  202. public:
  203. StringStack();
  204. virtual ~StringStack();
  205. void Push( const char* str );
  206. const char* Pop();
  207. int NumPositive() const { return nPositive; }
  208. private:
  209. DynArray< char, 50 > mem;
  210. int nPositive; // number of strings with len > 0
  211. };
  212. */
  213. /*
  214. class StringPool
  215. {
  216. public:
  217. enum { INIT_SIZE=20 };
  218. StringPool() : size( 0 ) {
  219. const char** mem = pool.PushArr( INIT_SIZE );
  220. memset( (void*)mem, 0, sizeof(char)*INIT_SIZE );
  221. }
  222. ~StringPool() {}
  223. const char* Intern( const char* str );
  224. private:
  225. // FNV hash
  226. int Hash( const char* s ) {
  227. #define FNV_32_PRIME ((int)0x01000193)
  228. int hval = 0;
  229. while (*s) {
  230. hval *= FNV_32_PRIME;
  231. hval ^= (int)*s++;
  232. }
  233. return hval;
  234. }
  235. int size;
  236. DynArray< const char*, INIT_SIZE > pool; // the hash table
  237. StringStack store; // memory for the interned strings
  238. };
  239. */
  240. class XMLBase
  241. {
  242. public:
  243. public:
  244. XMLBase() {}
  245. virtual ~XMLBase() {}
  246. static const char* SkipWhiteSpace( const char* p ) { while( isspace( *p ) ) { ++p; } return p; }
  247. static char* SkipWhiteSpace( char* p ) { while( isspace( *p ) ) { ++p; } return p; }
  248. inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) {
  249. int n = 0;
  250. if ( p == q ) {
  251. return true;
  252. }
  253. while( *p && *q && *p == *q && n<nChar ) {
  254. ++p; ++q; ++n;
  255. }
  256. if ( (n == nChar) || ( *p == 0 && *q == 0 ) ) {
  257. return true;
  258. }
  259. return false;
  260. }
  261. inline static int IsUTF8Continuation( unsigned char p ) { return p & 0x80; }
  262. inline static int IsAlphaNum( unsigned char anyByte ) { return ( anyByte <= 127 ) ? isalnum( anyByte ) : 1; }
  263. inline static int IsAlpha( unsigned char anyByte ) { return ( anyByte <= 127 ) ? isalpha( anyByte ) : 1; }
  264. static char* ParseText( char* in, StrPair* pair, const char* endTag, int strFlags );
  265. static char* ParseName( char* in, StrPair* pair );
  266. private:
  267. };
  268. class XMLNode
  269. {
  270. friend class XMLDocument;
  271. friend class XMLElement;
  272. public:
  273. //void* operator new( size_t size, MemPool* pool );
  274. //void operator delete( void* mem, MemPool* pool );
  275. XMLNode* InsertEndChild( XMLNode* addThis );
  276. virtual void Print( XMLStreamer* streamer );
  277. const char* Value() const { return value.GetStr(); }
  278. void SetValue( const char* val ) { value.SetInternedStr( val ); }
  279. virtual XMLElement* ToElement() { return 0; }
  280. virtual XMLText* ToText() { return 0; }
  281. virtual XMLComment* ToComment() { return 0; }
  282. XMLNode* FirstChild() { return firstChild; }
  283. XMLElement* FirstChildElement( const char* value=0 );
  284. // fixme: guarentee null terminator to avoid internal checks
  285. virtual char* ParseDeep( char* );
  286. void SetTextParent() { isTextParent = true; }
  287. bool IsTextParent() const { return isTextParent; }
  288. virtual bool IsClosingElement() const { return false; }
  289. protected:
  290. XMLNode( XMLDocument* );
  291. virtual ~XMLNode();
  292. void ClearChildren();
  293. XMLDocument* document;
  294. XMLNode* parent;
  295. bool isTextParent;
  296. mutable StrPair value;
  297. XMLNode* firstChild;
  298. XMLNode* lastChild;
  299. XMLNode* prev;
  300. XMLNode* next;
  301. private:
  302. MemPool* memPool;
  303. void Unlink( XMLNode* child );
  304. };
  305. class XMLText : public XMLNode
  306. {
  307. friend class XMLBase;
  308. friend class XMLDocument;
  309. public:
  310. virtual void Print( XMLStreamer* streamer );
  311. const char* Value() { return value.GetStr(); }
  312. void SetValue( const char* );
  313. virtual XMLText* ToText() { return this; }
  314. char* ParseDeep( char* );
  315. protected:
  316. XMLText( XMLDocument* doc ) : XMLNode( doc ) {}
  317. virtual ~XMLText() {}
  318. private:
  319. };
  320. class XMLComment : public XMLNode
  321. {
  322. friend class XMLBase;
  323. friend class XMLDocument;
  324. public:
  325. virtual void Print( XMLStreamer* );
  326. virtual XMLComment* ToComment() { return this; }
  327. const char* Value() { return value.GetStr(); }
  328. char* ParseDeep( char* );
  329. protected:
  330. XMLComment( XMLDocument* doc );
  331. virtual ~XMLComment();
  332. private:
  333. };
  334. class XMLAttribute : public XMLBase
  335. {
  336. friend class XMLElement;
  337. public:
  338. virtual void Print( XMLStreamer* streamer );
  339. private:
  340. XMLAttribute( XMLElement* element ) : next( 0 ) {}
  341. virtual ~XMLAttribute() {}
  342. char* ParseDeep( char* p );
  343. StrPair name;
  344. StrPair value;
  345. XMLAttribute* next;
  346. };
  347. class XMLElement : public XMLNode
  348. {
  349. friend class XMLBase;
  350. friend class XMLDocument;
  351. public:
  352. const char* Name() const { return Value(); }
  353. void SetName( const char* str ) { SetValue( str ); }
  354. virtual void Print( XMLStreamer* );
  355. virtual XMLElement* ToElement() { return this; }
  356. // internal:
  357. virtual bool IsClosingElement() const { return closing; }
  358. char* ParseDeep( char* p );
  359. protected:
  360. XMLElement( XMLDocument* doc );
  361. virtual ~XMLElement();
  362. private:
  363. char* ParseAttributes( char* p, bool *closedElement );
  364. bool closing;
  365. XMLAttribute* rootAttribute;
  366. XMLAttribute* lastAttribute;
  367. };
  368. class XMLDocument : public XMLNode
  369. {
  370. friend class XMLElement;
  371. public:
  372. XMLDocument();
  373. ~XMLDocument();
  374. int Parse( const char* );
  375. int Load( const char* );
  376. int Load( FILE* );
  377. void Print( XMLStreamer* streamer=0 );
  378. XMLElement* NewElement( const char* name );
  379. enum {
  380. NO_ERROR = 0,
  381. ERROR_ELEMENT_MISMATCH,
  382. ERROR_PARSING_ELEMENT,
  383. ERROR_PARSING_ATTRIBUTE
  384. };
  385. void SetError( int error, const char* str1, const char* str2 );
  386. bool Error() const { return errorID != NO_ERROR; }
  387. int GetErrorID() const { return errorID; }
  388. const char* GetErrorStr1() const { return errorStr1; }
  389. const char* GetErrorStr2() const { return errorStr2; }
  390. char* Identify( char* p, XMLNode** node );
  391. private:
  392. XMLDocument( const XMLDocument& ); // intentionally not implemented
  393. void InitDocument();
  394. int errorID;
  395. const char* errorStr1;
  396. const char* errorStr2;
  397. char* charBuffer;
  398. //StringStack stringPool;
  399. MemPoolT< sizeof(XMLElement) > elementPool;
  400. MemPoolT< sizeof(XMLAttribute) > attributePool;
  401. MemPoolT< sizeof(XMLText) > textPool;
  402. MemPoolT< sizeof(XMLComment) > commentPool;
  403. };
  404. class XMLStreamer
  405. {
  406. public:
  407. XMLStreamer( FILE* file );
  408. ~XMLStreamer() {}
  409. void OpenElement( const char* name, bool textParent );
  410. void PushAttribute( const char* name, const char* value );
  411. void CloseElement();
  412. void PushText( const char* text );
  413. void PushComment( const char* comment );
  414. private:
  415. void SealElement();
  416. void PrintSpace( int depth );
  417. void PrintString( const char* ); // prints out, after detecting entities.
  418. bool TextOnStack() const {
  419. for( int i=0; i<text.Size(); ++i ) {
  420. if ( text[i] == 'T' )
  421. return true;
  422. }
  423. return false;
  424. }
  425. FILE* fp;
  426. int depth;
  427. bool elementJustOpened;
  428. enum {
  429. ENTITY_RANGE = 64
  430. };
  431. bool entityFlag[ENTITY_RANGE];
  432. DynArray< const char*, 10 > stack;
  433. DynArray< char, 10 > text;
  434. };
  435. }; // tinyxml2
  436. #endif // TINYXML2_INCLUDED