tinyxml2/tinyxml2.cpp

254 lines
4.7 KiB
C++
Raw Normal View History

2011-12-28 19:42:49 -08:00
#include "tinyxml2.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
2011-12-31 14:58:18 -08:00
#include <ctype.h>
2011-12-28 19:42:49 -08:00
using namespace tinyxml2;
2012-01-14 18:08:12 -08:00
static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
static const char LF = LINE_FEED;
static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
static const char CR = CARRIAGE_RETURN;
// --------- CharBuffer ----------- //
2011-12-28 19:42:49 -08:00
/*static*/ CharBuffer* CharBuffer::Construct( const char* in )
{
size_t len = strlen( in );
size_t size = len + sizeof( CharBuffer );
CharBuffer* cb = (CharBuffer*) malloc( size );
cb->length = len;
strcpy( cb->mem, in );
return cb;
}
/*static*/ void CharBuffer::Free( CharBuffer* cb )
{
free( cb );
}
// --------- XMLNode ----------- //
XMLNode::XMLNode( XMLDocument* doc ) :
document( doc ),
parent( 0 ),
firstChild( 0 ), lastChild( 0 ),
prev( 0 ), next( 0 )
2011-12-31 14:58:18 -08:00
{
}
XMLNode::~XMLNode()
{
XMLNode* node=firstChild;
while( node ) {
XMLNode* temp = node->next;
delete node;
node = temp;
}
}
XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
{
if ( lastChild ) {
TIXMLASSERT( firstChild );
TIXMLASSERT( lastChild->next == 0 );
lastChild->next = addThis;
addThis->prev = lastChild;
lastChild = addThis;
addThis->parent = this;
2012-01-11 15:43:54 -08:00
addThis->next = 0;
}
else {
TIXMLASSERT( firstChild == 0 );
firstChild = lastChild = addThis;
addThis->parent = this;
addThis->prev = 0;
2012-01-11 15:43:54 -08:00
addThis->next = 0;
}
return addThis;
}
void XMLNode::Print( FILE* fp, int depth )
{
for( XMLNode* node = firstChild; node; node=node->next ) {
node->Print( fp, depth );
}
}
void XMLNode::PrintSpace( FILE* fp, int depth )
2012-01-11 15:43:54 -08:00
{
for( int i=0; i<depth; ++i ) {
fprintf( fp, " " );
2011-12-31 14:58:18 -08:00
}
}
const char* XMLNode::ParseText( char* p, const char* endTag, char** next )
{
TIXMLASSERT( endTag && *endTag );
2012-01-14 18:08:12 -08:00
char* start = p;
char* q = p; // q (target) <= p (src) in same buffer.
char endChar = *endTag;
int length = strlen( endTag );
char* nextTag = 0;
2012-01-14 18:08:12 -08:00
// Inner loop of text parsing.
while ( *p ) {
2012-01-14 18:08:12 -08:00
if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
*q = 0;
nextTag = p + length;
break;
}
else if ( *p == CR ) {
// CR-LF pair becomes LF
// CR alone becomes LF
// LF-CR becomes LF
if ( *(p+1) == LF ) {
p += 2;
}
else {
++p;
}
2012-01-14 18:08:12 -08:00
*q = LF;
}
2012-01-14 18:08:12 -08:00
else if ( *p == LF ) {
if ( *(p+1) == CR ) {
p += 2;
}
else {
++p;
}
*q = LF;
}
else {
*q = *p;
++p;
}
++q;
}
2012-01-14 18:08:12 -08:00
// Error? If we don't have a text tag, something went wrong. (Although
// what the nextTag points at may be null.)
if ( nextTag == 0 ) {
return 0;
}
*next = nextTag;
return start;
}
// --------- XMLComment ---------- //
XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
{
}
2012-01-11 15:43:54 -08:00
XMLComment::~XMLComment()
{
}
2012-01-11 15:43:54 -08:00
void XMLComment::Print( FILE* fp, int depth )
{
XMLNode::Print( fp, depth );
2012-01-14 18:08:12 -08:00
fprintf( fp, "<!--%s-->\n", value );
2012-01-11 15:43:54 -08:00
}
char* XMLComment::ParseDeep( char* p )
{
// Comment parses as text.
value = ParseText( p, "-->", &p );
2011-12-31 14:58:18 -08:00
return p;
}
// --------- XMLDocument ----------- //
2011-12-28 19:42:49 -08:00
XMLDocument::XMLDocument() :
charBuffer( 0 )
{
root = new XMLNode( this );
2011-12-28 19:42:49 -08:00
}
2011-12-28 14:36:55 -08:00
XMLDocument::~XMLDocument()
{
delete root;
delete charBuffer;
}
bool XMLDocument::Parse( const char* p )
{
2012-01-11 15:43:54 -08:00
charBuffer = CharBuffer::Construct( p );
XMLNode* node = 0;
2012-01-11 15:43:54 -08:00
char* q = Identify( charBuffer->mem, &node );
root->InsertEndChild( node );
2012-01-11 15:43:54 -08:00
node->ParseDeep( q );
2012-01-11 15:43:54 -08:00
return true;
}
2012-01-11 15:43:54 -08:00
void XMLDocument::Print( FILE* fp, int depth )
{
2012-01-11 15:43:54 -08:00
for( XMLNode* node = root->firstChild; node; node=node->next ) {
node->Print( fp, depth );
}
}
char* XMLDocument::Identify( char* p, XMLNode** node )
2011-12-28 14:36:55 -08:00
{
2011-12-31 14:58:18 -08:00
XMLNode* returnNode = 0;
p = XMLNode::SkipWhiteSpace( p );
if( !p || !*p || *p != '<' )
{
return 0;
}
// What is this thing?
// - Elements start with a letter or underscore, but xml is reserved.
// - Comments: <!--
// - Decleration: <?xml
// - Everthing else is unknown to tinyxml.
//
static const char* xmlHeader = { "<?xml" };
static const char* commentHeader = { "<!--" };
static const char* dtdHeader = { "<!" };
static const char* cdataHeader = { "<![CDATA[" };
static const int xmlHeaderLen = 5;
static const int commentHeaderLen = 4;
static const int dtdHeaderLen = 2;
static const int cdataHeaderLen = 9;
2011-12-31 14:58:18 -08:00
if ( XMLNode::StringEqual( p, commentHeader, commentHeaderLen ) ) {
2012-01-11 15:43:54 -08:00
returnNode = new XMLComment( this );
p += commentHeaderLen;
2011-12-31 14:58:18 -08:00
}
else {
TIXMLASSERT( 0 );
}
2011-12-28 14:36:55 -08:00
*node = returnNode;
return p;
2011-12-28 14:36:55 -08:00
}