blob: afd01f496835b5b03c354a42b67a67c11db9486a [file] [log] [blame]
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001#ifndef TINYXML2_INCLUDED
2#define TINYXML2_INCLUDED
3
Lee Thomason2c85a712012-01-31 08:24:24 -08004/*
5 TODO
6 - const and non-const versions of API
7 - memory pool the class construction
8 - attribute accessors
9 - node navigation
10 - handles
11 - visit pattern - change streamer?
12 - make constructors protected
13 - hide copy constructor
14 - hide = operator
15*/
16
U-Lama\Lee4cee6112011-12-31 14:58:18 -080017#include <limits.h>
Lee Thomasonce0763e2012-01-11 15:43:54 -080018#include <ctype.h>
19#include <stdio.h>
Lee Thomason2c85a712012-01-31 08:24:24 -080020#include <memory.h>
U-Lama\Lee4cee6112011-12-31 14:58:18 -080021
22#if defined( _DEBUG ) || defined( DEBUG ) || defined (__DEBUG__)
23 #ifndef DEBUG
24 #define DEBUG
25 #endif
26#endif
27
28
29#if defined(DEBUG)
30 #if defined(_MSC_VER)
31 #define TIXMLASSERT( x ) if ( !(x)) { _asm { int 3 } } //if ( !(x)) WinDebugBreak()
32 #elif defined (ANDROID_NDK)
33 #include <android/log.h>
34 #define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); }
35 #else
36 #include <assert.h>
37 #define TIXMLASSERT assert
38 #endif
39#else
40 #define TIXMLASSERT( x ) {}
41#endif
42
U-Lama\Leee13c3e62011-12-28 14:36:55 -080043
44namespace tinyxml2
45{
Lee Thomasonce0763e2012-01-11 15:43:54 -080046class XMLDocument;
Lee Thomason8a5dfee2012-01-18 17:43:40 -080047class XMLElement;
48class XMLAttribute;
49class XMLComment;
50class XMLNode;
Lee Thomason5492a1c2012-01-23 15:32:10 -080051class XMLText;
U-Lama\Leee13c3e62011-12-28 14:36:55 -080052
Lee Thomason5cae8972012-01-24 18:03:07 -080053class XMLStreamer;
54
Lee Thomason39ede242012-01-20 11:27:56 -080055class StrPair
56{
Lee Thomasond34f52c2012-01-20 12:55:24 -080057public:
Lee Thomason39ede242012-01-20 11:27:56 -080058 enum {
Lee Thomasone4422302012-01-20 17:59:50 -080059 NEEDS_ENTITY_PROCESSING = 0x01,
Lee Thomason18d68bd2012-01-26 18:17:26 -080060 NEEDS_NEWLINE_NORMALIZATION = 0x02,
61
62 TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
63 ATTRIBUTE_NAME = 0,
64 ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
65 COMMENT = NEEDS_NEWLINE_NORMALIZATION,
Lee Thomason39ede242012-01-20 11:27:56 -080066 };
67
68 StrPair() : flags( 0 ), start( 0 ), end( 0 ) {}
Lee Thomasone4422302012-01-20 17:59:50 -080069 void Set( char* start, char* end, int flags ) {
Lee Thomason39ede242012-01-20 11:27:56 -080070 this->start = start; this->end = end; this->flags = flags | NEEDS_FLUSH;
71 }
72 const char* GetStr();
Lee Thomasone4422302012-01-20 17:59:50 -080073 bool Empty() const { return start == end; }
Lee Thomason39ede242012-01-20 11:27:56 -080074
Lee Thomason2c85a712012-01-31 08:24:24 -080075 void SetInternedStr( const char* str ) { this->start = (char*) str; this->end = 0; this->flags = 0; }
76
Lee Thomason39ede242012-01-20 11:27:56 -080077private:
Lee Thomasone4422302012-01-20 17:59:50 -080078 enum {
79 NEEDS_FLUSH = 0x100
80 };
81
Lee Thomason39ede242012-01-20 11:27:56 -080082 // After parsing, if *end != 0, it can be set to zero.
83 int flags;
Lee Thomasone4422302012-01-20 17:59:50 -080084 char* start;
Lee Thomason39ede242012-01-20 11:27:56 -080085 char* end;
86};
87
U-Lama\Lee560bd472011-12-28 19:42:49 -080088
Lee Thomason2c85a712012-01-31 08:24:24 -080089template <class T, int INIT>
90class DynArray
91{
92public:
93 DynArray< T, INIT >()
94 {
95 mem = pool;
96 allocated = INIT;
97 size = 0;
98 }
99 ~DynArray()
100 {
101 if ( mem != pool ) {
102 delete mem;
103 }
104 }
105 void Push( T t )
106 {
107 EnsureCapacity( size+1 );
108 mem[size++] = t;
109 }
110
111 T* PushArr( int count )
112 {
113 EnsureCapacity( size+count );
114 T* ret = &mem[size];
115 size += count;
116 return ret;
117 }
118 T Pop() {
119 return mem[--size];
120 }
121 void PopArr( int count )
122 {
123 TIXMLASSERT( size >= count );
124 size -= count;
125 }
126
127 bool Empty() const { return size == 0; }
128 T& operator[](int i) { TIXMLASSERT( i>= 0 && i < size ); return mem[i]; }
129 const T& operator[](int i) const { TIXMLASSERT( i>= 0 && i < size ); return mem[i]; }
130 int Size() const { return size; }
131 const T* Mem() const { return mem; }
132 T* Mem() { return mem; }
133
134
135private:
136 void EnsureCapacity( int cap ) {
137 if ( cap > allocated ) {
138 int newAllocated = cap * 2;
139 T* newMem = new T[newAllocated];
140 memcpy( newMem, mem, sizeof(T)*size ); // warning: not using constructors, only works for PODs
141 if ( mem != pool ) delete [] mem;
142 mem = newMem;
143 allocated = newAllocated;
144 }
145 }
146
147 T* mem;
148 T pool[INIT];
149 int allocated; // objects allocated
150 int size; // number objects in use
151};
152
153
154/*
155class StringStack
156{
157public:
158 StringStack();
159 virtual ~StringStack();
160
161 void Push( const char* str );
162 const char* Pop();
163
164 int NumPositive() const { return nPositive; }
165
166private:
167 DynArray< char, 50 > mem;
168 int nPositive; // number of strings with len > 0
169};
170*/
171
172/*
173class StringPool
174{
175public:
176 enum { INIT_SIZE=20 };
177
178 StringPool() : size( 0 ) {
179 const char** mem = pool.PushArr( INIT_SIZE );
180 memset( (void*)mem, 0, sizeof(char)*INIT_SIZE );
181 }
182 ~StringPool() {}
183
184 const char* Intern( const char* str );
185
186private:
187 // FNV hash
188 int Hash( const char* s ) {
189 #define FNV_32_PRIME ((int)0x01000193)
190 int hval = 0;
191 while (*s) {
192 hval *= FNV_32_PRIME;
193 hval ^= (int)*s++;
194 }
195 return hval;
196 }
197
198 int size;
199 DynArray< const char*, INIT_SIZE > pool; // the hash table
200 StringStack store; // memory for the interned strings
201};
202*/
203
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800204class XMLBase
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800205{
206public:
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800207 XMLBase() {}
208 virtual ~XMLBase() {}
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800209
210protected:
Lee Thomason3f57d272012-01-11 15:30:03 -0800211 static const char* SkipWhiteSpace( const char* p ) { while( isspace( *p ) ) { ++p; } return p; }
212 static char* SkipWhiteSpace( char* p ) { while( isspace( *p ) ) { ++p; } return p; }
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800213
214 inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) {
215 int n = 0;
Lee Thomasond34f52c2012-01-20 12:55:24 -0800216 if ( p == q ) {
217 return true;
218 }
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800219 while( *p && *q && *p == *q && n<nChar ) {
220 ++p; ++q; ++n;
221 }
222 if ( (n == nChar) || ( *p == 0 && *q == 0 ) ) {
223 return true;
224 }
225 return false;
226 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800227 inline static int IsUTF8Continuation( unsigned char p ) { return p & 0x80; }
228 inline static int IsAlphaNum( unsigned char anyByte ) { return ( anyByte <= 127 ) ? isalnum( anyByte ) : 1; }
229 inline static int IsAlpha( unsigned char anyByte ) { return ( anyByte <= 127 ) ? isalpha( anyByte ) : 1; }
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800230
Lee Thomason18d68bd2012-01-26 18:17:26 -0800231 char* ParseText( char* in, StrPair* pair, const char* endTag, int strFlags );
Lee Thomason39ede242012-01-20 11:27:56 -0800232 char* ParseName( char* in, StrPair* pair );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800233 char* Identify( XMLDocument* document, char* p, XMLNode** node );
234};
235
Lee Thomason5cae8972012-01-24 18:03:07 -0800236
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800237class XMLNode : public XMLBase
238{
239 friend class XMLDocument;
240 friend class XMLElement;
241public:
242 virtual ~XMLNode();
243
244 XMLNode* InsertEndChild( XMLNode* addThis );
Lee Thomason5cae8972012-01-24 18:03:07 -0800245 virtual void Print( XMLStreamer* streamer );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800246
Lee Thomason2c85a712012-01-31 08:24:24 -0800247 const char* Value() const { return value.GetStr(); }
248 void SetValue( const char* val ) { value.SetInternedStr( val ); }
249
Lee Thomason5492a1c2012-01-23 15:32:10 -0800250 virtual XMLElement* ToElement() { return 0; }
251 virtual XMLText* ToText() { return 0; }
252 virtual XMLComment* ToComment() { return 0; }
Lee Thomason3f57d272012-01-11 15:30:03 -0800253
Lee Thomason2c85a712012-01-31 08:24:24 -0800254 XMLNode* FirstChild() { return firstChild; }
255 XMLElement* FirstChildElement( const char* value=0 );
256
Lee Thomason67d61312012-01-24 16:01:51 -0800257 // fixme: guarentee null terminator to avoid internal checks
258 virtual char* ParseDeep( char* );
259
260 void SetTextParent() { isTextParent = true; }
261 bool IsTextParent() const { return isTextParent; }
262 virtual bool IsClosingElement() const { return false; }
Lee Thomason3f57d272012-01-11 15:30:03 -0800263
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800264protected:
265 XMLNode( XMLDocument* );
Lee Thomason18d68bd2012-01-26 18:17:26 -0800266 void ClearChildren();
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800267
Lee Thomason3f57d272012-01-11 15:30:03 -0800268 XMLDocument* document;
269 XMLNode* parent;
Lee Thomason67d61312012-01-24 16:01:51 -0800270 bool isTextParent;
Lee Thomason2c85a712012-01-31 08:24:24 -0800271 mutable StrPair value;
Lee Thomason3f57d272012-01-11 15:30:03 -0800272
273 XMLNode* firstChild;
274 XMLNode* lastChild;
275
276 XMLNode* prev;
277 XMLNode* next;
278
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800279private:
Lee Thomason18d68bd2012-01-26 18:17:26 -0800280 void Unlink( XMLNode* child );
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800281};
282
283
Lee Thomason5492a1c2012-01-23 15:32:10 -0800284class XMLText : public XMLNode
285{
Lee Thomason2c85a712012-01-31 08:24:24 -0800286 friend class XMLBase;
287 friend class XMLDocument;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800288public:
Lee Thomason5492a1c2012-01-23 15:32:10 -0800289 virtual ~XMLText() {}
Lee Thomason5cae8972012-01-24 18:03:07 -0800290 virtual void Print( XMLStreamer* streamer );
Lee Thomason5492a1c2012-01-23 15:32:10 -0800291 const char* Value() { return value.GetStr(); }
Lee Thomason2c85a712012-01-31 08:24:24 -0800292 void SetValue( const char* );
293
Lee Thomason5492a1c2012-01-23 15:32:10 -0800294 virtual XMLText* ToText() { return this; }
295
296 char* ParseDeep( char* );
297
298protected:
Lee Thomason2c85a712012-01-31 08:24:24 -0800299 XMLText( XMLDocument* doc ) : XMLNode( doc ) {}
Lee Thomason5492a1c2012-01-23 15:32:10 -0800300
301private:
Lee Thomason5492a1c2012-01-23 15:32:10 -0800302};
303
304
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800305class XMLComment : public XMLNode
306{
Lee Thomason2c85a712012-01-31 08:24:24 -0800307 friend class XMLBase;
308 friend class XMLDocument;
Lee Thomason3f57d272012-01-11 15:30:03 -0800309public:
Lee Thomason3f57d272012-01-11 15:30:03 -0800310 virtual ~XMLComment();
Lee Thomason5cae8972012-01-24 18:03:07 -0800311 virtual void Print( XMLStreamer* );
Lee Thomason5492a1c2012-01-23 15:32:10 -0800312 virtual XMLComment* ToComment() { return this; }
Lee Thomasonce0763e2012-01-11 15:43:54 -0800313
Lee Thomasond34f52c2012-01-20 12:55:24 -0800314 const char* Value() { return value.GetStr(); }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800315
Lee Thomasonce0763e2012-01-11 15:43:54 -0800316 char* ParseDeep( char* );
317
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800318protected:
Lee Thomason2c85a712012-01-31 08:24:24 -0800319 XMLComment( XMLDocument* doc );
320
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800321
Lee Thomason3f57d272012-01-11 15:30:03 -0800322private:
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800323};
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800324
325
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800326class XMLAttribute : public XMLBase
327{
328 friend class XMLElement;
329public:
Lee Thomasond34f52c2012-01-20 12:55:24 -0800330 XMLAttribute( XMLElement* element ) : next( 0 ) {}
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800331 virtual ~XMLAttribute() {}
Lee Thomason5cae8972012-01-24 18:03:07 -0800332 virtual void Print( XMLStreamer* streamer );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800333
334private:
335 char* ParseDeep( char* p );
336
Lee Thomason22aead12012-01-23 13:29:35 -0800337 StrPair name;
Lee Thomasond34f52c2012-01-20 12:55:24 -0800338 StrPair value;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800339 XMLAttribute* next;
340};
341
342
343class XMLElement : public XMLNode
344{
Lee Thomason2c85a712012-01-31 08:24:24 -0800345 friend class XMLBase;
346 friend class XMLDocument;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800347public:
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800348 virtual ~XMLElement();
349
Lee Thomason2c85a712012-01-31 08:24:24 -0800350 const char* Name() const { return Value(); }
351 void SetName( const char* str ) { SetValue( str ); }
352
Lee Thomason5cae8972012-01-24 18:03:07 -0800353 virtual void Print( XMLStreamer* );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800354
355 virtual XMLElement* ToElement() { return this; }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800356
Lee Thomason2c85a712012-01-31 08:24:24 -0800357 // internal:
358 virtual bool IsClosingElement() const { return closing; }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800359 char* ParseDeep( char* p );
360
361protected:
Lee Thomason2c85a712012-01-31 08:24:24 -0800362 XMLElement( XMLDocument* doc );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800363
364private:
Lee Thomason67d61312012-01-24 16:01:51 -0800365 char* ParseAttributes( char* p, bool *closedElement );
366
Lee Thomason2c85a712012-01-31 08:24:24 -0800367 mutable StrPair name;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800368 bool closing;
369 XMLAttribute* rootAttribute;
370 XMLAttribute* lastAttribute;
371};
372
373
Lee Thomason67d61312012-01-24 16:01:51 -0800374class XMLDocument : public XMLNode
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800375{
376public:
Lee Thomason18d68bd2012-01-26 18:17:26 -0800377 XMLDocument();
Lee Thomason3f57d272012-01-11 15:30:03 -0800378 ~XMLDocument();
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800379
Lee Thomason7c913cd2012-01-26 18:32:34 -0800380 int Parse( const char* );
381 int Load( const char* );
382 int Load( FILE* );
Lee Thomason18d68bd2012-01-26 18:17:26 -0800383
Lee Thomason5cae8972012-01-24 18:03:07 -0800384 void Print( XMLStreamer* streamer=0 );
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800385
Lee Thomason2c85a712012-01-31 08:24:24 -0800386 XMLElement* NewElement( const char* name );
387
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800388 enum {
Lee Thomason18d68bd2012-01-26 18:17:26 -0800389 NO_ERROR = 0,
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800390 ERROR_ELEMENT_MISMATCH,
391 ERROR_PARSING_ELEMENT,
392 ERROR_PARSING_ATTRIBUTE
393 };
Lee Thomason67d61312012-01-24 16:01:51 -0800394 void SetError( int error, const char* str1, const char* str2 );
Lee Thomason18d68bd2012-01-26 18:17:26 -0800395
Lee Thomason7c913cd2012-01-26 18:32:34 -0800396 bool Error() const { return errorID != NO_ERROR; }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800397 int GetErrorID() const { return errorID; }
398 const char* GetErrorStr1() const { return errorStr1; }
399 const char* GetErrorStr2() const { return errorStr2; }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800400
Lee Thomason2c85a712012-01-31 08:24:24 -0800401// const char* Intern( const char* );
402
Lee Thomason3f57d272012-01-11 15:30:03 -0800403private:
404 XMLDocument( const XMLDocument& ); // intentionally not implemented
Lee Thomason18d68bd2012-01-26 18:17:26 -0800405 void InitDocument();
406
Lee Thomason7c913cd2012-01-26 18:32:34 -0800407 int errorID;
Lee Thomason18d68bd2012-01-26 18:17:26 -0800408 const char* errorStr1;
409 const char* errorStr2;
410 char* charBuffer;
Lee Thomason2c85a712012-01-31 08:24:24 -0800411 //StringStack stringPool;
Lee Thomason5cae8972012-01-24 18:03:07 -0800412};
413
Lee Thomason7c913cd2012-01-26 18:32:34 -0800414
Lee Thomason5cae8972012-01-24 18:03:07 -0800415class XMLStreamer
416{
417public:
418 XMLStreamer( FILE* file );
419 ~XMLStreamer() {}
420
421 void OpenElement( const char* name, bool textParent );
422 void PushAttribute( const char* name, const char* value );
423 void CloseElement();
424
425 void PushText( const char* text );
426 void PushComment( const char* comment );
427
428private:
429 void SealElement();
430 void PrintSpace( int depth );
Lee Thomason857b8682012-01-25 17:50:25 -0800431 void PrintString( const char* ); // prints out, after detecting entities.
Lee Thomason2c85a712012-01-31 08:24:24 -0800432 bool TextOnStack() const {
433 for( int i=0; i<text.Size(); ++i ) {
434 if ( text[i] == 'T' )
435 return true;
436 }
437 return false;
438 }
Lee Thomason5cae8972012-01-24 18:03:07 -0800439
440 FILE* fp;
441 int depth;
442 bool elementJustOpened;
Lee Thomason857b8682012-01-25 17:50:25 -0800443 enum {
Lee Thomason951d8832012-01-26 08:47:06 -0800444 ENTITY_RANGE = 64
Lee Thomason857b8682012-01-25 17:50:25 -0800445 };
446 bool entityFlag[ENTITY_RANGE];
Lee Thomason5cae8972012-01-24 18:03:07 -0800447
Lee Thomason2c85a712012-01-31 08:24:24 -0800448 DynArray< const char*, 10 > stack;
449 DynArray< char, 10 > text;
Lee Thomason5cae8972012-01-24 18:03:07 -0800450};
451
452
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800453}; // tinyxml2
454
U-Lama\Lee560bd472011-12-28 19:42:49 -0800455
456
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800457#endif // TINYXML2_INCLUDED