2011-12-28 22:36:55 +00:00
|
|
|
#ifndef TINYXML2_INCLUDED
|
|
|
|
#define TINYXML2_INCLUDED
|
|
|
|
|
2011-12-31 22:58:18 +00:00
|
|
|
#include <limits.h>
|
2012-01-11 23:43:54 +00:00
|
|
|
#include <ctype.h>
|
|
|
|
#include <stdio.h>
|
2011-12-31 22:58:18 +00:00
|
|
|
|
|
|
|
#if defined( _DEBUG ) || defined( DEBUG ) || defined (__DEBUG__)
|
|
|
|
#ifndef DEBUG
|
|
|
|
#define DEBUG
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#if defined(DEBUG)
|
|
|
|
#if defined(_MSC_VER)
|
|
|
|
#define TIXMLASSERT( x ) if ( !(x)) { _asm { int 3 } } //if ( !(x)) WinDebugBreak()
|
|
|
|
#elif defined (ANDROID_NDK)
|
|
|
|
#include <android/log.h>
|
|
|
|
#define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); }
|
|
|
|
#else
|
|
|
|
#include <assert.h>
|
|
|
|
#define TIXMLASSERT assert
|
|
|
|
#endif
|
|
|
|
#else
|
|
|
|
#define TIXMLASSERT( x ) {}
|
|
|
|
#endif
|
|
|
|
|
2011-12-28 22:36:55 +00:00
|
|
|
|
|
|
|
namespace tinyxml2
|
|
|
|
{
|
2012-01-11 23:43:54 +00:00
|
|
|
class XMLDocument;
|
2012-01-19 01:43:40 +00:00
|
|
|
class XMLElement;
|
|
|
|
class XMLAttribute;
|
|
|
|
class XMLComment;
|
|
|
|
class XMLNode;
|
2012-01-23 23:32:10 +00:00
|
|
|
class XMLText;
|
2011-12-28 22:36:55 +00:00
|
|
|
|
2012-01-25 02:03:07 +00:00
|
|
|
class XMLStreamer;
|
|
|
|
|
2011-12-29 03:42:49 +00:00
|
|
|
// internal - move to separate namespace
|
|
|
|
struct CharBuffer
|
|
|
|
{
|
|
|
|
size_t length;
|
|
|
|
char mem[1];
|
|
|
|
|
|
|
|
static CharBuffer* Construct( const char* in );
|
|
|
|
static void Free( CharBuffer* );
|
|
|
|
};
|
|
|
|
|
2012-01-20 19:27:56 +00:00
|
|
|
// FIXME: refactor to be the basis for all string handling.
|
|
|
|
class StrPair
|
|
|
|
{
|
2012-01-20 20:55:24 +00:00
|
|
|
public:
|
2012-01-20 19:27:56 +00:00
|
|
|
enum {
|
2012-01-21 01:59:50 +00:00
|
|
|
NEEDS_ENTITY_PROCESSING = 0x01,
|
|
|
|
NEEDS_NEWLINE_NORMALIZATION = 0x02
|
2012-01-20 19:27:56 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
StrPair() : flags( 0 ), start( 0 ), end( 0 ) {}
|
2012-01-21 01:59:50 +00:00
|
|
|
void Set( char* start, char* end, int flags ) {
|
2012-01-20 19:27:56 +00:00
|
|
|
this->start = start; this->end = end; this->flags = flags | NEEDS_FLUSH;
|
|
|
|
}
|
|
|
|
const char* GetStr();
|
2012-01-21 01:59:50 +00:00
|
|
|
bool Empty() const { return start == end; }
|
2012-01-20 19:27:56 +00:00
|
|
|
|
|
|
|
private:
|
2012-01-21 01:59:50 +00:00
|
|
|
enum {
|
|
|
|
NEEDS_FLUSH = 0x100
|
|
|
|
};
|
|
|
|
|
2012-01-20 19:27:56 +00:00
|
|
|
// After parsing, if *end != 0, it can be set to zero.
|
|
|
|
int flags;
|
2012-01-21 01:59:50 +00:00
|
|
|
char* start;
|
2012-01-20 19:27:56 +00:00
|
|
|
char* end;
|
|
|
|
};
|
|
|
|
|
2011-12-29 03:42:49 +00:00
|
|
|
|
2012-01-19 01:43:40 +00:00
|
|
|
class XMLBase
|
2011-12-28 22:36:55 +00:00
|
|
|
{
|
|
|
|
public:
|
2012-01-19 01:43:40 +00:00
|
|
|
XMLBase() {}
|
|
|
|
virtual ~XMLBase() {}
|
2011-12-31 22:58:18 +00:00
|
|
|
|
|
|
|
protected:
|
2012-01-11 23:30:03 +00:00
|
|
|
static const char* SkipWhiteSpace( const char* p ) { while( isspace( *p ) ) { ++p; } return p; }
|
|
|
|
static char* SkipWhiteSpace( char* p ) { while( isspace( *p ) ) { ++p; } return p; }
|
2011-12-31 22:58:18 +00:00
|
|
|
|
|
|
|
inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) {
|
|
|
|
int n = 0;
|
2012-01-20 20:55:24 +00:00
|
|
|
if ( p == q ) {
|
|
|
|
return true;
|
|
|
|
}
|
2011-12-31 22:58:18 +00:00
|
|
|
while( *p && *q && *p == *q && n<nChar ) {
|
|
|
|
++p; ++q; ++n;
|
|
|
|
}
|
|
|
|
if ( (n == nChar) || ( *p == 0 && *q == 0 ) ) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2012-01-19 01:43:40 +00:00
|
|
|
inline static int IsUTF8Continuation( unsigned char p ) { return p & 0x80; }
|
|
|
|
inline static int IsAlphaNum( unsigned char anyByte ) { return ( anyByte <= 127 ) ? isalnum( anyByte ) : 1; }
|
|
|
|
inline static int IsAlpha( unsigned char anyByte ) { return ( anyByte <= 127 ) ? isalpha( anyByte ) : 1; }
|
|
|
|
|
2012-01-21 01:59:50 +00:00
|
|
|
char* ParseText( char* in, StrPair* pair, const char* endTag );
|
2012-01-20 19:27:56 +00:00
|
|
|
char* ParseName( char* in, StrPair* pair );
|
2012-01-19 01:43:40 +00:00
|
|
|
char* Identify( XMLDocument* document, char* p, XMLNode** node );
|
|
|
|
};
|
|
|
|
|
2012-01-25 02:03:07 +00:00
|
|
|
|
2012-01-19 01:43:40 +00:00
|
|
|
class XMLNode : public XMLBase
|
|
|
|
{
|
|
|
|
friend class XMLDocument;
|
|
|
|
friend class XMLElement;
|
|
|
|
public:
|
|
|
|
virtual ~XMLNode();
|
|
|
|
|
|
|
|
XMLNode* InsertEndChild( XMLNode* addThis );
|
2012-01-25 02:03:07 +00:00
|
|
|
virtual void Print( XMLStreamer* streamer );
|
2012-01-19 01:43:40 +00:00
|
|
|
|
2012-01-23 23:32:10 +00:00
|
|
|
virtual XMLElement* ToElement() { return 0; }
|
|
|
|
virtual XMLText* ToText() { return 0; }
|
|
|
|
virtual XMLComment* ToComment() { return 0; }
|
2012-01-11 23:30:03 +00:00
|
|
|
|
2012-01-25 00:01:51 +00:00
|
|
|
// fixme: guarentee null terminator to avoid internal checks
|
|
|
|
virtual char* ParseDeep( char* );
|
|
|
|
|
|
|
|
void SetTextParent() { isTextParent = true; }
|
|
|
|
bool IsTextParent() const { return isTextParent; }
|
|
|
|
virtual bool IsClosingElement() const { return false; }
|
2012-01-11 23:30:03 +00:00
|
|
|
|
2012-01-19 01:43:40 +00:00
|
|
|
protected:
|
|
|
|
XMLNode( XMLDocument* );
|
2012-01-23 16:44:25 +00:00
|
|
|
void Unlink( XMLNode* child );
|
2012-01-19 01:43:40 +00:00
|
|
|
|
2012-01-11 23:30:03 +00:00
|
|
|
XMLDocument* document;
|
|
|
|
XMLNode* parent;
|
2012-01-25 00:01:51 +00:00
|
|
|
bool isTextParent;
|
2012-01-11 23:30:03 +00:00
|
|
|
|
|
|
|
XMLNode* firstChild;
|
|
|
|
XMLNode* lastChild;
|
|
|
|
|
|
|
|
XMLNode* prev;
|
|
|
|
XMLNode* next;
|
|
|
|
|
2011-12-31 22:58:18 +00:00
|
|
|
private:
|
2011-12-28 22:36:55 +00:00
|
|
|
};
|
2011-12-29 03:42:49 +00:00
|
|
|
|
2011-12-28 22:36:55 +00:00
|
|
|
|
2012-01-23 23:32:10 +00:00
|
|
|
class XMLText : public XMLNode
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
XMLText( XMLDocument* doc ) : XMLNode( doc ) {}
|
|
|
|
virtual ~XMLText() {}
|
|
|
|
|
2012-01-25 02:03:07 +00:00
|
|
|
virtual void Print( XMLStreamer* streamer );
|
2012-01-23 23:32:10 +00:00
|
|
|
const char* Value() { return value.GetStr(); }
|
|
|
|
virtual XMLText* ToText() { return this; }
|
|
|
|
|
|
|
|
char* ParseDeep( char* );
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
|
|
|
private:
|
|
|
|
StrPair value;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2011-12-31 22:58:18 +00:00
|
|
|
class XMLComment : public XMLNode
|
|
|
|
{
|
2012-01-11 23:30:03 +00:00
|
|
|
public:
|
|
|
|
XMLComment( XMLDocument* doc );
|
|
|
|
virtual ~XMLComment();
|
2011-12-31 22:58:18 +00:00
|
|
|
|
2012-01-25 02:03:07 +00:00
|
|
|
virtual void Print( XMLStreamer* );
|
2012-01-23 23:32:10 +00:00
|
|
|
virtual XMLComment* ToComment() { return this; }
|
2012-01-11 23:43:54 +00:00
|
|
|
|
2012-01-20 20:55:24 +00:00
|
|
|
const char* Value() { return value.GetStr(); }
|
2012-01-19 01:43:40 +00:00
|
|
|
|
2012-01-11 23:43:54 +00:00
|
|
|
char* ParseDeep( char* );
|
|
|
|
|
2012-01-19 01:43:40 +00:00
|
|
|
protected:
|
|
|
|
|
|
|
|
private:
|
2012-01-20 20:55:24 +00:00
|
|
|
StrPair value;
|
2012-01-19 01:43:40 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class XMLAttribute : public XMLBase
|
|
|
|
{
|
|
|
|
friend class XMLElement;
|
|
|
|
public:
|
2012-01-20 20:55:24 +00:00
|
|
|
XMLAttribute( XMLElement* element ) : next( 0 ) {}
|
2012-01-19 01:43:40 +00:00
|
|
|
virtual ~XMLAttribute() {}
|
2012-01-25 02:03:07 +00:00
|
|
|
virtual void Print( XMLStreamer* streamer );
|
2012-01-19 01:43:40 +00:00
|
|
|
|
2012-01-11 23:30:03 +00:00
|
|
|
private:
|
2012-01-19 01:43:40 +00:00
|
|
|
char* ParseDeep( char* p );
|
|
|
|
|
2012-01-23 21:29:35 +00:00
|
|
|
StrPair name;
|
2012-01-20 20:55:24 +00:00
|
|
|
StrPair value;
|
2012-01-19 01:43:40 +00:00
|
|
|
XMLAttribute* next;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class XMLElement : public XMLNode
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
XMLElement( XMLDocument* doc );
|
|
|
|
virtual ~XMLElement();
|
|
|
|
|
2012-01-20 20:55:24 +00:00
|
|
|
const char* Name() { return name.GetStr(); }
|
2012-01-25 02:03:07 +00:00
|
|
|
virtual void Print( XMLStreamer* );
|
2012-01-19 01:43:40 +00:00
|
|
|
|
|
|
|
virtual XMLElement* ToElement() { return this; }
|
2012-01-25 00:01:51 +00:00
|
|
|
virtual bool IsClosingElement() const { return closing; }
|
2012-01-19 01:43:40 +00:00
|
|
|
|
|
|
|
char* ParseDeep( char* p );
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
|
|
|
private:
|
2012-01-25 00:01:51 +00:00
|
|
|
char* ParseAttributes( char* p, bool *closedElement );
|
|
|
|
|
2012-01-20 20:55:24 +00:00
|
|
|
StrPair name;
|
2012-01-19 01:43:40 +00:00
|
|
|
bool closing;
|
|
|
|
XMLAttribute* rootAttribute;
|
|
|
|
XMLAttribute* lastAttribute;
|
2011-12-31 22:58:18 +00:00
|
|
|
};
|
|
|
|
|
2011-12-28 22:36:55 +00:00
|
|
|
|
2012-01-25 00:01:51 +00:00
|
|
|
class XMLDocument : public XMLNode
|
2011-12-28 22:36:55 +00:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
XMLDocument();
|
2012-01-11 23:30:03 +00:00
|
|
|
~XMLDocument();
|
2011-12-28 22:36:55 +00:00
|
|
|
|
|
|
|
bool Parse( const char* );
|
2012-01-25 02:03:07 +00:00
|
|
|
void Print( XMLStreamer* streamer=0 );
|
2011-12-28 22:36:55 +00:00
|
|
|
|
2012-01-25 00:01:51 +00:00
|
|
|
/*
|
2012-01-11 23:30:03 +00:00
|
|
|
XMLNode* Root() { return root; }
|
|
|
|
XMLNode* RootElement();
|
2012-01-25 00:01:51 +00:00
|
|
|
*/
|
2012-01-19 01:43:40 +00:00
|
|
|
enum {
|
|
|
|
ERROR_ELEMENT_MISMATCH,
|
|
|
|
ERROR_PARSING_ELEMENT,
|
|
|
|
ERROR_PARSING_ATTRIBUTE
|
|
|
|
};
|
2012-01-25 00:01:51 +00:00
|
|
|
void SetError( int error, const char* str1, const char* str2 );
|
2012-01-19 01:43:40 +00:00
|
|
|
|
2011-12-28 22:36:55 +00:00
|
|
|
private:
|
2012-01-11 23:30:03 +00:00
|
|
|
XMLDocument( const XMLDocument& ); // intentionally not implemented
|
2011-12-29 03:42:49 +00:00
|
|
|
CharBuffer* charBuffer;
|
2011-12-28 22:36:55 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2012-01-26 01:16:23 +00:00
|
|
|
// FIXME: break out into string pointer stack
|
2012-01-25 02:03:07 +00:00
|
|
|
class StringStack
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
StringStack();
|
2012-01-26 01:16:23 +00:00
|
|
|
~StringStack();
|
2012-01-25 02:03:07 +00:00
|
|
|
|
|
|
|
void Push( const char* str );
|
|
|
|
const char* Pop();
|
|
|
|
|
|
|
|
int NumPositive() const { return nPositive; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
enum {
|
|
|
|
INIT=10 // fixme, super small for testing
|
|
|
|
};
|
|
|
|
char* mem;
|
2012-01-26 01:16:23 +00:00
|
|
|
char pool[INIT];
|
2012-01-25 02:03:07 +00:00
|
|
|
int inUse; // includes null
|
|
|
|
int allocated; // bytes allocated
|
|
|
|
int nPositive; // number of strings with len > 0
|
|
|
|
};
|
|
|
|
|
|
|
|
class XMLStreamer
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
XMLStreamer( FILE* file );
|
|
|
|
~XMLStreamer() {}
|
|
|
|
|
|
|
|
void OpenElement( const char* name, bool textParent );
|
|
|
|
void PushAttribute( const char* name, const char* value );
|
|
|
|
void CloseElement();
|
|
|
|
|
|
|
|
void PushText( const char* text );
|
|
|
|
void PushComment( const char* comment );
|
|
|
|
|
|
|
|
private:
|
|
|
|
void SealElement();
|
|
|
|
void PrintSpace( int depth );
|
2012-01-26 01:50:25 +00:00
|
|
|
void PrintString( const char* ); // prints out, after detecting entities.
|
2012-01-25 02:03:07 +00:00
|
|
|
|
|
|
|
FILE* fp;
|
|
|
|
int depth;
|
|
|
|
bool elementJustOpened;
|
2012-01-26 01:50:25 +00:00
|
|
|
enum {
|
|
|
|
ENTITY_RANGE = 64,
|
|
|
|
};
|
|
|
|
bool entityFlag[ENTITY_RANGE];
|
2012-01-25 02:03:07 +00:00
|
|
|
|
|
|
|
StringStack stack;
|
|
|
|
StringStack text;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2011-12-29 03:42:49 +00:00
|
|
|
}; // tinyxml2
|
2011-12-28 22:36:55 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endif // TINYXML2_INCLUDED
|