tinyxml2.h 9.8 KB

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