Updated TinyXML

https://github.com/leethomason/tinyxml2
This commit is contained in:
PKEuS 2015-08-08 18:38:56 +02:00
parent e71ab70356
commit fc19c6ca11
2 changed files with 419 additions and 296 deletions

View File

@ -26,10 +26,81 @@ distribution.
#include <new> // yes, this one new style header, is in the Android SDK. #include <new> // yes, this one new style header, is in the Android SDK.
#if defined(ANDROID_NDK) || defined(__QNXNTO__) #if defined(ANDROID_NDK) || defined(__QNXNTO__)
# include <stddef.h> # include <stddef.h>
# include <stdarg.h>
#else #else
# include <cstddef> # include <cstddef>
# include <cstdarg>
#endif #endif
#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
// Microsoft Visual Studio, version 2005 and higher. Not WinCE.
/*int _snprintf_s(
char *buffer,
size_t sizeOfBuffer,
size_t count,
const char *format [,
argument] ...
);*/
inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... )
{
va_list va;
va_start( va, format );
int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
va_end( va );
return result;
}
inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va )
{
int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
return result;
}
#define TIXML_VSCPRINTF _vscprintf
#define TIXML_SSCANF sscanf_s
#elif defined _MSC_VER
// Microsoft Visual Studio 2003 and earlier or WinCE
#define TIXML_SNPRINTF _snprintf
#define TIXML_VSNPRINTF _vsnprintf
#define TIXML_SSCANF sscanf
#if (_MSC_VER < 1400 ) && (!defined WINCE)
// Microsoft Visual Studio 2003 and not WinCE.
#define TIXML_VSCPRINTF _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have.
#else
// Microsoft Visual Studio 2003 and earlier or WinCE.
inline int TIXML_VSCPRINTF( const char* format, va_list va )
{
int len = 512;
for (;;) {
len = len*2;
char* str = new char[len]();
const int required = _vsnprintf(str, len, format, va);
delete[] str;
if ( required != -1 ) {
TIXMLASSERT( required >= 0 );
len = required;
break;
}
}
TIXMLASSERT( len >= 0 );
return len;
}
#endif
#else
// GCC version 3 and higher
//#warning( "Using sn* functions." )
#define TIXML_SNPRINTF snprintf
#define TIXML_VSNPRINTF vsnprintf
inline int TIXML_VSCPRINTF( const char* format, va_list va )
{
int len = vsnprintf( 0, 0, format, va );
TIXMLASSERT( len >= 0 );
return len;
}
#define TIXML_SSCANF sscanf
#endif
static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
static const char LF = LINE_FEED; static const char LF = LINE_FEED;
static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
@ -140,19 +211,19 @@ char* StrPair::ParseName( char* p )
if ( !p || !(*p) ) { if ( !p || !(*p) ) {
return 0; return 0;
} }
if ( !XMLUtil::IsNameStartChar( *p ) ) {
return 0;
}
char* const start = p; char* const start = p;
++p;
while( *p && ( p == start ? XMLUtil::IsNameStartChar( *p ) : XMLUtil::IsNameChar( *p ) )) { while ( *p && XMLUtil::IsNameChar( *p ) ) {
++p; ++p;
} }
if ( p > start ) {
Set( start, p, 0 ); Set( start, p, 0 );
return p; return p;
} }
return 0;
}
void StrPair::CollapseWhitespace() void StrPair::CollapseWhitespace()
@ -162,7 +233,7 @@ void StrPair::CollapseWhitespace()
// Trim leading space. // Trim leading space.
_start = XMLUtil::SkipWhiteSpace( _start ); _start = XMLUtil::SkipWhiteSpace( _start );
if ( _start && *_start ) { if ( *_start ) {
char* p = _start; // the read pointer char* p = _start; // the read pointer
char* q = _start; // the write pointer char* q = _start; // the write pointer
@ -186,6 +257,8 @@ void StrPair::CollapseWhitespace()
const char* StrPair::GetStr() const char* StrPair::GetStr()
{ {
TIXMLASSERT( _start );
TIXMLASSERT( _end );
if ( _flags & NEEDS_FLUSH ) { if ( _flags & NEEDS_FLUSH ) {
*_end = 0; *_end = 0;
_flags ^= NEEDS_FLUSH; _flags ^= NEEDS_FLUSH;
@ -226,15 +299,23 @@ const char* StrPair::GetStr()
const int buflen = 10; const int buflen = 10;
char buf[buflen] = { 0 }; char buf[buflen] = { 0 };
int len = 0; int len = 0;
p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) ); char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
if ( adjusted == 0 ) {
*q = *p;
++p;
++q;
}
else {
TIXMLASSERT( 0 <= len && len <= buflen ); TIXMLASSERT( 0 <= len && len <= buflen );
TIXMLASSERT( q + len <= p ); TIXMLASSERT( q + len <= adjusted );
p = adjusted;
memcpy( q, buf, len ); memcpy( q, buf, len );
q += len; q += len;
} }
}
else { else {
int i=0; bool entityFound = false;
for(; i<NUM_ENTITIES; ++i ) { for( int i = 0; i < NUM_ENTITIES; ++i ) {
const Entity& entity = entities[i]; const Entity& entity = entities[i];
if ( strncmp( p + 1, entity.pattern, entity.length ) == 0 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
&& *( p + entity.length + 1 ) == ';' ) { && *( p + entity.length + 1 ) == ';' ) {
@ -242,10 +323,11 @@ const char* StrPair::GetStr()
*q = entity.value; *q = entity.value;
++q; ++q;
p += entity.length + 2; p += entity.length + 2;
entityFound = true;
break; break;
} }
} }
if ( i == NUM_ENTITIES ) { if ( !entityFound ) {
// fixme: treat as error? // fixme: treat as error?
++p; ++p;
++q; ++q;
@ -262,11 +344,12 @@ const char* StrPair::GetStr()
} }
// The loop below has plenty going on, and this // The loop below has plenty going on, and this
// is a less useful mode. Break it out. // is a less useful mode. Break it out.
if ( _flags & COLLAPSE_WHITESPACE ) { if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
CollapseWhitespace(); CollapseWhitespace();
} }
_flags = (_flags & NEEDS_DELETE); _flags = (_flags & NEEDS_DELETE);
} }
TIXMLASSERT( _start );
return _start; return _start;
} }
@ -277,6 +360,8 @@ const char* StrPair::GetStr()
const char* XMLUtil::ReadBOM( const char* p, bool* bom ) const char* XMLUtil::ReadBOM( const char* p, bool* bom )
{ {
TIXMLASSERT( p );
TIXMLASSERT( bom );
*bom = false; *bom = false;
const unsigned char* pu = reinterpret_cast<const unsigned char*>(p); const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
// Check for BOM: // Check for BOM:
@ -286,6 +371,7 @@ const char* XMLUtil::ReadBOM( const char* p, bool* bom )
*bom = true; *bom = true;
p += 3; p += 3;
} }
TIXMLASSERT( p );
return p; return p;
} }
@ -309,7 +395,7 @@ void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length
*length = 4; *length = 4;
} }
else { else {
*length = 0; // This code won't covert this correctly anyway. *length = 0; // This code won't convert this correctly anyway.
return; return;
} }
@ -332,8 +418,9 @@ void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length
case 1: case 1:
--output; --output;
*output = (char)(input | FIRST_BYTE_MARK[*length]); *output = (char)(input | FIRST_BYTE_MARK[*length]);
default:
break; break;
default:
TIXMLASSERT( false );
} }
} }
@ -345,65 +432,83 @@ const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
if ( *(p+1) == '#' && *(p+2) ) { if ( *(p+1) == '#' && *(p+2) ) {
unsigned long ucs = 0; unsigned long ucs = 0;
TIXMLASSERT( sizeof( ucs ) >= 4 );
ptrdiff_t delta = 0; ptrdiff_t delta = 0;
unsigned mult = 1; unsigned mult = 1;
static const char SEMICOLON = ';';
if ( *(p+2) == 'x' ) { if ( *(p+2) == 'x' ) {
// Hexadecimal. // Hexadecimal.
if ( !*(p+3) ) {
return 0;
}
const char* q = p+3; const char* q = p+3;
q = strchr( q, ';' ); if ( !(*q) ) {
if ( !q || !*q ) {
return 0; return 0;
} }
q = strchr( q, SEMICOLON );
if ( !q ) {
return 0;
}
TIXMLASSERT( *q == SEMICOLON );
delta = q-p; delta = q-p;
--q; --q;
while ( *q != 'x' ) { while ( *q != 'x' ) {
unsigned int digit = 0;
if ( *q >= '0' && *q <= '9' ) { if ( *q >= '0' && *q <= '9' ) {
ucs += mult * (*q - '0'); digit = *q - '0';
} }
else if ( *q >= 'a' && *q <= 'f' ) { else if ( *q >= 'a' && *q <= 'f' ) {
ucs += mult * (*q - 'a' + 10); digit = *q - 'a' + 10;
} }
else if ( *q >= 'A' && *q <= 'F' ) { else if ( *q >= 'A' && *q <= 'F' ) {
ucs += mult * (*q - 'A' + 10 ); digit = *q - 'A' + 10;
} }
else { else {
return 0; return 0;
} }
TIXMLASSERT( digit >= 0 && digit < 16);
TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
const unsigned int digitScaled = mult * digit;
TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
ucs += digitScaled;
TIXMLASSERT( mult <= UINT_MAX / 16 );
mult *= 16; mult *= 16;
--q; --q;
} }
} }
else { else {
// Decimal. // Decimal.
if ( !*(p+2) ) {
return 0;
}
const char* q = p+2; const char* q = p+2;
q = strchr( q, ';' ); if ( !(*q) ) {
if ( !q || !*q ) {
return 0; return 0;
} }
q = strchr( q, SEMICOLON );
if ( !q ) {
return 0;
}
TIXMLASSERT( *q == SEMICOLON );
delta = q-p; delta = q-p;
--q; --q;
while ( *q != '#' ) { while ( *q != '#' ) {
if ( *q >= '0' && *q <= '9' ) { if ( *q >= '0' && *q <= '9' ) {
ucs += mult * (*q - '0'); const unsigned int digit = *q - '0';
TIXMLASSERT( digit >= 0 && digit < 10);
TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
const unsigned int digitScaled = mult * digit;
TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
ucs += digitScaled;
} }
else { else {
return 0; return 0;
} }
TIXMLASSERT( mult <= UINT_MAX / 10 );
mult *= 10; mult *= 10;
--q; --q;
} }
@ -503,35 +608,31 @@ bool XMLUtil::ToDouble( const char* str, double* value )
char* XMLDocument::Identify( char* p, XMLNode** node ) char* XMLDocument::Identify( char* p, XMLNode** node )
{ {
TIXMLASSERT( node );
TIXMLASSERT( p );
char* const start = p; char* const start = p;
p = XMLUtil::SkipWhiteSpace( p ); p = XMLUtil::SkipWhiteSpace( p );
if( !p || !*p ) { if( !*p ) {
*node = 0;
TIXMLASSERT( p );
return p; return p;
} }
// What is this thing? // These strings define the matching patterns:
// These strings define the matching patters:
static const char* xmlHeader = { "<?" }; static const char* xmlHeader = { "<?" };
static const char* commentHeader = { "<!--" }; static const char* commentHeader = { "<!--" };
static const char* dtdHeader = { "<!" };
static const char* cdataHeader = { "<![CDATA[" }; static const char* cdataHeader = { "<![CDATA[" };
static const char* dtdHeader = { "<!" };
static const char* elementHeader = { "<" }; // and a header for everything else; check last. static const char* elementHeader = { "<" }; // and a header for everything else; check last.
static const int xmlHeaderLen = 2; static const int xmlHeaderLen = 2;
static const int commentHeaderLen = 4; static const int commentHeaderLen = 4;
static const int dtdHeaderLen = 2;
static const int cdataHeaderLen = 9; static const int cdataHeaderLen = 9;
static const int dtdHeaderLen = 2;
static const int elementHeaderLen = 1; static const int elementHeaderLen = 1;
#if defined(_MSC_VER)
#pragma warning ( push )
#pragma warning ( disable : 4127 )
#endif
TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
#if defined(_MSC_VER)
#pragma warning (pop)
#endif
XMLNode* returnNode = 0; XMLNode* returnNode = 0;
if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) { if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() ); TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
@ -572,6 +673,8 @@ char* XMLDocument::Identify( char* p, XMLNode** node )
p = start; // Back it up, all the text counts. p = start; // Back it up, all the text counts.
} }
TIXMLASSERT( returnNode );
TIXMLASSERT( p );
*node = returnNode; *node = returnNode;
return p; return p;
} }
@ -579,6 +682,7 @@ char* XMLDocument::Identify( char* p, XMLNode** node )
bool XMLDocument::Accept( XMLVisitor* visitor ) const bool XMLDocument::Accept( XMLVisitor* visitor ) const
{ {
TIXMLASSERT( visitor );
if ( visitor->VisitEnter( *this ) ) { if ( visitor->VisitEnter( *this ) ) {
for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) { for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
if ( !node->Accept( visitor ) ) { if ( !node->Accept( visitor ) ) {
@ -612,6 +716,9 @@ XMLNode::~XMLNode()
const char* XMLNode::Value() const const char* XMLNode::Value() const
{ {
// Catch an edge case: XMLDocuments don't have a a Value. Carefully return nullptr.
if ( this->ToDocument() )
return 0;
return _value.GetStr(); return _value.GetStr();
} }
@ -629,6 +736,7 @@ void XMLNode::SetValue( const char* str, bool staticMem )
void XMLNode::DeleteChildren() void XMLNode::DeleteChildren()
{ {
while( _firstChild ) { while( _firstChild ) {
TIXMLASSERT( _lastChild );
TIXMLASSERT( _firstChild->_document == _document ); TIXMLASSERT( _firstChild->_document == _document );
XMLNode* node = _firstChild; XMLNode* node = _firstChild;
Unlink( node ); Unlink( node );
@ -641,7 +749,9 @@ void XMLNode::DeleteChildren()
void XMLNode::Unlink( XMLNode* child ) void XMLNode::Unlink( XMLNode* child )
{ {
TIXMLASSERT( child );
TIXMLASSERT( child->_document == _document ); TIXMLASSERT( child->_document == _document );
TIXMLASSERT( child->_parent == this );
if ( child == _firstChild ) { if ( child == _firstChild ) {
_firstChild = _firstChild->_next; _firstChild = _firstChild->_next;
} }
@ -661,6 +771,7 @@ void XMLNode::Unlink( XMLNode* child )
void XMLNode::DeleteChild( XMLNode* node ) void XMLNode::DeleteChild( XMLNode* node )
{ {
TIXMLASSERT( node );
TIXMLASSERT( node->_document == _document ); TIXMLASSERT( node->_document == _document );
TIXMLASSERT( node->_parent == this ); TIXMLASSERT( node->_parent == this );
DeleteNode( node ); DeleteNode( node );
@ -674,11 +785,7 @@ XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
TIXMLASSERT( false ); TIXMLASSERT( false );
return 0; return 0;
} }
InsertChildPreamble( addThis );
if (addThis->_parent)
addThis->_parent->Unlink( addThis );
else
addThis->_memPool->SetTracked();
if ( _lastChild ) { if ( _lastChild ) {
TIXMLASSERT( _firstChild ); TIXMLASSERT( _firstChild );
@ -708,11 +815,7 @@ XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
TIXMLASSERT( false ); TIXMLASSERT( false );
return 0; return 0;
} }
InsertChildPreamble( addThis );
if (addThis->_parent)
addThis->_parent->Unlink( addThis );
else
addThis->_memPool->SetTracked();
if ( _firstChild ) { if ( _firstChild ) {
TIXMLASSERT( _lastChild ); TIXMLASSERT( _lastChild );
@ -755,10 +858,7 @@ XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
// The last node or the only node. // The last node or the only node.
return InsertEndChild( addThis ); return InsertEndChild( addThis );
} }
if (addThis->_parent) InsertChildPreamble( addThis );
addThis->_parent->Unlink( addThis );
else
addThis->_memPool->SetTracked();
addThis->_prev = afterThis; addThis->_prev = afterThis;
addThis->_next = afterThis->_next; addThis->_next = afterThis->_next;
afterThis->_next->_prev = addThis; afterThis->_next->_prev = addThis;
@ -770,12 +870,12 @@ XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
const XMLElement* XMLNode::FirstChildElement( const char* value ) const const XMLElement* XMLNode::FirstChildElement( const char* name ) const
{ {
for( XMLNode* node=_firstChild; node; node=node->_next ) { for( const XMLNode* node = _firstChild; node; node = node->_next ) {
XMLElement* element = node->ToElement(); const XMLElement* element = node->ToElement();
if ( element ) { if ( element ) {
if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) { if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {
return element; return element;
} }
} }
@ -784,12 +884,12 @@ const XMLElement* XMLNode::FirstChildElement( const char* value ) const
} }
const XMLElement* XMLNode::LastChildElement( const char* value ) const const XMLElement* XMLNode::LastChildElement( const char* name ) const
{ {
for( XMLNode* node=_lastChild; node; node=node->_prev ) { for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
XMLElement* element = node->ToElement(); const XMLElement* element = node->ToElement();
if ( element ) { if ( element ) {
if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) { if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {
return element; return element;
} }
} }
@ -798,12 +898,12 @@ const XMLElement* XMLNode::LastChildElement( const char* value ) const
} }
const XMLElement* XMLNode::NextSiblingElement( const char* value ) const const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
{ {
for( XMLNode* node=this->_next; node; node = node->_next ) { for( const XMLNode* node = _next; node; node = node->_next ) {
const XMLElement* element = node->ToElement(); const XMLElement* element = node->ToElement();
if ( element if ( element
&& (!value || XMLUtil::StringEqual( value, node->Value() ))) { && (!name || XMLUtil::StringEqual( name, element->Name() ))) {
return element; return element;
} }
} }
@ -811,12 +911,12 @@ const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
} }
const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
{ {
for( XMLNode* node=_prev; node; node = node->_prev ) { for( const XMLNode* node = _prev; node; node = node->_prev ) {
const XMLElement* element = node->ToElement(); const XMLElement* element = node->ToElement();
if ( element if ( element
&& (!value || XMLUtil::StringEqual( value, node->Value() ))) { && (!name || XMLUtil::StringEqual( name, element->Name() ))) {
return element; return element;
} }
} }
@ -847,7 +947,7 @@ char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
XMLNode* node = 0; XMLNode* node = 0;
p = _document->Identify( p, &node ); p = _document->Identify( p, &node );
if ( p == 0 || node == 0 ) { if ( node == 0 ) {
break; break;
} }
@ -855,16 +955,27 @@ char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
p = node->ParseDeep( p, &endTag ); p = node->ParseDeep( p, &endTag );
if ( !p ) { if ( !p ) {
DeleteNode( node ); DeleteNode( node );
node = 0;
if ( !_document->Error() ) { if ( !_document->Error() ) {
_document->SetError( XML_ERROR_PARSING, 0, 0 ); _document->SetError( XML_ERROR_PARSING, 0, 0 );
} }
break; break;
} }
XMLDeclaration* decl = node->ToDeclaration();
if ( decl ) {
// A declaration can only be the first child of a document.
// Set error, if document already has children.
if ( !_document->NoChildren() ) {
_document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0);
DeleteNode( decl );
break;
}
}
XMLElement* ele = node->ToElement(); XMLElement* ele = node->ToElement();
if ( ele ) {
// We read the end tag. Return it to the parent. // We read the end tag. Return it to the parent.
if ( ele && ele->ClosingType() == XMLElement::CLOSING ) { if ( ele->ClosingType() == XMLElement::CLOSING ) {
if ( parentEnd ) { if ( parentEnd ) {
ele->_value.TransferTo( parentEnd ); ele->_value.TransferTo( parentEnd );
} }
@ -875,31 +986,27 @@ char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
// Handle an end tag returned to this level. // Handle an end tag returned to this level.
// And handle a bunch of annoying errors. // And handle a bunch of annoying errors.
if ( ele ) {
bool mismatch = false; bool mismatch = false;
if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) { if ( endTag.Empty() ) {
if ( ele->ClosingType() == XMLElement::OPEN ) {
mismatch = true; mismatch = true;
} }
else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) { }
else {
if ( ele->ClosingType() != XMLElement::OPEN ) {
mismatch = true; mismatch = true;
} }
else if ( !endTag.Empty() ) { else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
mismatch = true; mismatch = true;
} }
} }
if ( mismatch ) { if ( mismatch ) {
_document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 ); _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0 );
p = 0;
}
}
if ( p == 0 ) {
DeleteNode( node ); DeleteNode( node );
node = 0; break;
} }
if ( node ) {
this->InsertEndChild( node );
} }
InsertEndChild( node );
} }
return 0; return 0;
} }
@ -914,6 +1021,17 @@ void XMLNode::DeleteNode( XMLNode* node )
pool->Free( node ); pool->Free( node );
} }
void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
{
TIXMLASSERT( insertThis );
TIXMLASSERT( insertThis->_document == _document );
if ( insertThis->_parent )
insertThis->_parent->Unlink( insertThis );
else
insertThis->_memPool->SetTracked();
}
// --------- XMLText ---------- // // --------- XMLText ---------- //
char* XMLText::ParseDeep( char* p, StrPair* ) char* XMLText::ParseDeep( char* p, StrPair* )
{ {
@ -928,16 +1046,16 @@ char* XMLText::ParseDeep( char* p, StrPair* )
else { else {
int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES; int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) { if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
flags |= StrPair::COLLAPSE_WHITESPACE; flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
} }
p = _value.ParseText( p, "<", flags ); p = _value.ParseText( p, "<", flags );
if ( !p ) {
_document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
}
if ( p && *p ) { if ( p && *p ) {
return p-1; return p-1;
} }
if ( !p ) {
_document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
}
} }
return 0; return 0;
} }
@ -1138,7 +1256,7 @@ char* XMLAttribute::ParseDeep( char* p, bool processEntities )
// Skip white space before = // Skip white space before =
p = XMLUtil::SkipWhiteSpace( p ); p = XMLUtil::SkipWhiteSpace( p );
if ( !p || *p != '=' ) { if ( *p != '=' ) {
return 0; return 0;
} }
@ -1474,7 +1592,7 @@ char* XMLElement::ParseAttributes( char* p )
// Read the attributes. // Read the attributes.
while( p ) { while( p ) {
p = XMLUtil::SkipWhiteSpace( p ); p = XMLUtil::SkipWhiteSpace( p );
if ( !p || !(*p) ) { if ( !(*p) ) {
_document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() ); _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
return 0; return 0;
} }
@ -1506,15 +1624,15 @@ char* XMLElement::ParseAttributes( char* p )
prevAttribute = attrib; prevAttribute = attrib;
} }
// end of the tag // end of the tag
else if ( *p == '/' && *(p+1) == '>' ) {
_closingType = CLOSED;
return p+2; // done; sealed element.
}
// end of the tag
else if ( *p == '>' ) { else if ( *p == '>' ) {
++p; ++p;
break; break;
} }
// end of the tag
else if ( *p == '/' && *(p+1) == '>' ) {
_closingType = CLOSED;
return p+2; // done; sealed element.
}
else { else {
_document->SetError( XML_ERROR_PARSING_ELEMENT, start, p ); _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
return 0; return 0;
@ -1541,9 +1659,6 @@ char* XMLElement::ParseDeep( char* p, StrPair* strPair )
{ {
// Read the element name. // Read the element name.
p = XMLUtil::SkipWhiteSpace( p ); p = XMLUtil::SkipWhiteSpace( p );
if ( !p ) {
return 0;
}
// The closing element is the </element> form. It is // The closing element is the </element> form. It is
// parsed just like a regular element then deleted from // parsed just like a regular element then deleted from
@ -1586,7 +1701,7 @@ bool XMLElement::ShallowEqual( const XMLNode* compare ) const
{ {
TIXMLASSERT( compare ); TIXMLASSERT( compare );
const XMLElement* other = compare->ToElement(); const XMLElement* other = compare->ToElement();
if ( other && XMLUtil::StringEqual( other->Value(), Value() )) { if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
const XMLAttribute* a=FirstAttribute(); const XMLAttribute* a=FirstAttribute();
const XMLAttribute* b=other->FirstAttribute(); const XMLAttribute* b=other->FirstAttribute();
@ -1659,7 +1774,8 @@ XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
_errorStr2( 0 ), _errorStr2( 0 ),
_charBuffer( 0 ) _charBuffer( 0 )
{ {
_document = this; // avoid warning about 'this' in initializer list // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
_document = this;
} }
@ -1816,12 +1932,18 @@ XMLError XMLDocument::LoadFile( FILE* fp )
return _errorID; return _errorID;
} }
const size_t size = filelength; if ( (unsigned long)filelength >= (size_t)-1 ) {
if ( size == 0 ) { // Cannot handle files which won't fit in buffer together with null terminator
SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
return _errorID;
}
if ( filelength == 0 ) {
SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
return _errorID; return _errorID;
} }
const size_t size = filelength;
_charBuffer = new char[size+1]; _charBuffer = new char[size+1];
size_t read = fread( _charBuffer, 1, size, fp ); size_t read = fread( _charBuffer, 1, size, fp );
if ( read != size ) { if ( read != size ) {
@ -1831,15 +1953,7 @@ XMLError XMLDocument::LoadFile( FILE* fp )
_charBuffer[size] = 0; _charBuffer[size] = 0;
const char* p = _charBuffer; Parse();
p = XMLUtil::SkipWhiteSpace( p );
p = XMLUtil::ReadBOM( p, &_writeBOM );
if ( !p || !*p ) {
SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
return _errorID;
}
ParseDeep( _charBuffer + (p-_charBuffer), 0 );
return _errorID; return _errorID;
} }
@ -1859,6 +1973,9 @@ XMLError XMLDocument::SaveFile( const char* filename, bool compact )
XMLError XMLDocument::SaveFile( FILE* fp, bool compact ) XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
{ {
// Clear any error from the last save, otherwise it will get reported
// for *this* call.
SetError( XML_NO_ERROR, 0, 0 );
XMLPrinter stream( fp, compact ); XMLPrinter stream( fp, compact );
Print( &stream ); Print( &stream );
return _errorID; return _errorID;
@ -1867,7 +1984,6 @@ XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
XMLError XMLDocument::Parse( const char* p, size_t len ) XMLError XMLDocument::Parse( const char* p, size_t len )
{ {
const char* start = p;
Clear(); Clear();
if ( len == 0 || !p || !*p ) { if ( len == 0 || !p || !*p ) {
@ -1881,15 +1997,7 @@ XMLError XMLDocument::Parse( const char* p, size_t len )
memcpy( _charBuffer, p, len ); memcpy( _charBuffer, p, len );
_charBuffer[len] = 0; _charBuffer[len] = 0;
p = XMLUtil::SkipWhiteSpace( p ); Parse();
p = XMLUtil::ReadBOM( p, &_writeBOM );
if ( !p || !*p ) {
SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
return _errorID;
}
ptrdiff_t delta = p - start; // skip initial whitespace, BOM, etc.
ParseDeep( _charBuffer+delta, 0 );
if ( Error() ) { if ( Error() ) {
// clean up now essentially dangling memory. // clean up now essentially dangling memory.
// and the parse fail can put objects in the // and the parse fail can put objects in the
@ -1906,12 +2014,14 @@ XMLError XMLDocument::Parse( const char* p, size_t len )
void XMLDocument::Print( XMLPrinter* streamer ) const void XMLDocument::Print( XMLPrinter* streamer ) const
{ {
XMLPrinter stdStreamer( stdout ); if ( streamer ) {
if ( !streamer ) {
streamer = &stdStreamer;
}
Accept( streamer ); Accept( streamer );
} }
else {
XMLPrinter stdoutStreamer( stdout );
Accept( &stdoutStreamer );
}
}
void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 ) void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
@ -1925,7 +2035,9 @@ void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
const char* XMLDocument::ErrorName() const const char* XMLDocument::ErrorName() const
{ {
TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT ); TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
return _errorNames[_errorID]; const char* errorName = _errorNames[_errorID];
TIXMLASSERT( errorName && errorName[0] );
return errorName;
} }
void XMLDocument::PrintError() const void XMLDocument::PrintError() const
@ -1942,11 +2054,27 @@ void XMLDocument::PrintError() const
TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 ); TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
} }
// Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
// causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n", printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
_errorID, ErrorName(), buf1, buf2 ); static_cast<int>( _errorID ), ErrorName(), buf1, buf2 );
} }
} }
void XMLDocument::Parse()
{
TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
TIXMLASSERT( _charBuffer );
char* p = _charBuffer;
p = XMLUtil::SkipWhiteSpace( p );
p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
if ( !*p ) {
SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
return;
}
ParseDeep(p, 0 );
}
XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) : XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
_elementJustOpened( false ), _elementJustOpened( false ),
@ -1962,16 +2090,13 @@ XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
_restrictedEntityFlag[i] = false; _restrictedEntityFlag[i] = false;
} }
for( int i=0; i<NUM_ENTITIES; ++i ) { for( int i=0; i<NUM_ENTITIES; ++i ) {
TIXMLASSERT( entities[i].value < ENTITY_RANGE ); const char entityValue = entities[i].value;
if ( entities[i].value < ENTITY_RANGE ) { TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
_entityFlag[ (int)entities[i].value ] = true; _entityFlag[ (unsigned char)entityValue ] = true;
} }
} _restrictedEntityFlag[(unsigned char)'&'] = true;
// Clang doesn't like indexing arrays with 'char' _restrictedEntityFlag[(unsigned char)'<'] = true;
// so cast to int. (Looks strange.) _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
_restrictedEntityFlag[(int)'&'] = true;
_restrictedEntityFlag[(int)'<'] = true;
_restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
_buffer.Push( 0 ); _buffer.Push( 0 );
} }
@ -1985,34 +2110,14 @@ void XMLPrinter::Print( const char* format, ... )
vfprintf( _fp, format, va ); vfprintf( _fp, format, va );
} }
else { else {
#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) const int len = TIXML_VSCPRINTF( format, va );
#if defined(WINCE)
int len = 512;
do {
len = len*2;
char* str = new char[len]();
len = _vsnprintf(str, len, format, va);
delete[] str;
}while (len < 0);
#else
int len = _vscprintf( format, va );
#endif
#else
int len = vsnprintf( 0, 0, format, va );
#endif
// Close out and re-start the va-args // Close out and re-start the va-args
va_end( va ); va_end( va );
TIXMLASSERT( len >= 0 );
va_start( va, format ); va_start( va, format );
TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator. char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) TIXML_VSNPRINTF( p, len+1, format, va );
#if defined(WINCE)
_vsnprintf( p, len+1, format, va );
#else
vsnprintf_s( p, len+1, _TRUNCATE, format, va );
#endif
#else
vsnprintf( p, len+1, format, va );
#endif
} }
va_end( va ); va_end( va );
} }
@ -2030,35 +2135,47 @@ void XMLPrinter::PrintString( const char* p, bool restricted )
{ {
// Look for runs of bytes between entities to print. // Look for runs of bytes between entities to print.
const char* q = p; const char* q = p;
const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
if ( _processEntities ) { if ( _processEntities ) {
const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
while ( *q ) { while ( *q ) {
TIXMLASSERT( p <= q );
// Remember, char is sometimes signed. (How many times has that bitten me?) // Remember, char is sometimes signed. (How many times has that bitten me?)
if ( *q > 0 && *q < ENTITY_RANGE ) { if ( *q > 0 && *q < ENTITY_RANGE ) {
// Check for entities. If one is found, flush // Check for entities. If one is found, flush
// the stream up until the entity, write the // the stream up until the entity, write the
// entity, and keep looking. // entity, and keep looking.
if ( flag[(unsigned)(*q)] ) { if ( flag[(unsigned char)(*q)] ) {
while ( p < q ) { while ( p < q ) {
Print( "%c", *p ); const size_t delta = q - p;
++p; // %.*s accepts type int as "precision"
const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Print( "%.*s", toPrint, p );
p += toPrint;
} }
bool entityPatternPrinted = false;
for( int i=0; i<NUM_ENTITIES; ++i ) { for( int i=0; i<NUM_ENTITIES; ++i ) {
if ( entities[i].value == *q ) { if ( entities[i].value == *q ) {
Print( "&%s;", entities[i].pattern ); Print( "&%s;", entities[i].pattern );
entityPatternPrinted = true;
break; break;
} }
} }
if ( !entityPatternPrinted ) {
// TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
TIXMLASSERT( false );
}
++p; ++p;
} }
} }
++q; ++q;
TIXMLASSERT( p <= q );
} }
} }
// Flush the remaining string. This will be the entire // Flush the remaining string. This will be the entire
// string if an entity wasn't found. // string if an entity wasn't found.
if ( !_processEntities || (q-p > 0) ) { TIXMLASSERT( p <= q );
if ( !_processEntities || ( p < q ) ) {
Print( "%s", p ); Print( "%s", p );
} }
} }
@ -2078,9 +2195,7 @@ void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
void XMLPrinter::OpenElement( const char* name, bool compactMode ) void XMLPrinter::OpenElement( const char* name, bool compactMode )
{ {
if ( _elementJustOpened ) { SealElementIfJustOpened();
SealElement();
}
_stack.Push( name ); _stack.Push( name );
if ( _textDepth < 0 && !_firstElement && !compactMode ) { if ( _textDepth < 0 && !_firstElement && !compactMode ) {
@ -2164,8 +2279,11 @@ void XMLPrinter::CloseElement( bool compactMode )
} }
void XMLPrinter::SealElement() void XMLPrinter::SealElementIfJustOpened()
{ {
if ( !_elementJustOpened ) {
return;
}
_elementJustOpened = false; _elementJustOpened = false;
Print( ">" ); Print( ">" );
} }
@ -2175,13 +2293,9 @@ void XMLPrinter::PushText( const char* text, bool cdata )
{ {
_textDepth = _depth-1; _textDepth = _depth-1;
if ( _elementJustOpened ) { SealElementIfJustOpened();
SealElement();
}
if ( cdata ) { if ( cdata ) {
Print( "<![CDATA[" ); Print( "<![CDATA[%s]]>", text );
Print( "%s", text );
Print( "]]>" );
} }
else { else {
PrintString( text, true ); PrintString( text, true );
@ -2230,9 +2344,7 @@ void XMLPrinter::PushText( double value )
void XMLPrinter::PushComment( const char* comment ) void XMLPrinter::PushComment( const char* comment )
{ {
if ( _elementJustOpened ) { SealElementIfJustOpened();
SealElement();
}
if ( _textDepth < 0 && !_firstElement && !_compactMode) { if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Print( "\n" ); Print( "\n" );
PrintSpace( _depth ); PrintSpace( _depth );
@ -2244,9 +2356,7 @@ void XMLPrinter::PushComment( const char* comment )
void XMLPrinter::PushDeclaration( const char* value ) void XMLPrinter::PushDeclaration( const char* value )
{ {
if ( _elementJustOpened ) { SealElementIfJustOpened();
SealElement();
}
if ( _textDepth < 0 && !_firstElement && !_compactMode) { if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Print( "\n" ); Print( "\n" );
PrintSpace( _depth ); PrintSpace( _depth );
@ -2258,9 +2368,7 @@ void XMLPrinter::PushDeclaration( const char* value )
void XMLPrinter::PushUnknown( const char* value ) void XMLPrinter::PushUnknown( const char* value )
{ {
if ( _elementJustOpened ) { SealElementIfJustOpened();
SealElement();
}
if ( _textDepth < 0 && !_firstElement && !_compactMode) { if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Print( "\n" ); Print( "\n" );
PrintSpace( _depth ); PrintSpace( _depth );
@ -2282,8 +2390,11 @@ bool XMLPrinter::VisitEnter( const XMLDocument& doc )
bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute ) bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
{ {
const XMLElement* parentElem = element.Parent()->ToElement(); const XMLElement* parentElem = 0;
bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode; if ( element.Parent() ) {
parentElem = element.Parent()->ToElement();
}
const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
OpenElement( element.Name(), compactMode ); OpenElement( element.Name(), compactMode );
while ( attribute ) { while ( attribute ) {
PushAttribute( attribute->Name(), attribute->Value() ); PushAttribute( attribute->Name(), attribute->Value() );

View File

@ -30,14 +30,12 @@ distribution.
# include <stdio.h> # include <stdio.h>
# include <stdlib.h> # include <stdlib.h>
# include <string.h> # include <string.h>
# include <stdarg.h>
#else #else
# include <cctype> # include <cctype>
# include <climits> # include <climits>
# include <cstdio> # include <cstdio>
# include <cstdlib> # include <cstdlib>
# include <cstring> # include <cstring>
# include <cstdarg>
#endif #endif
/* /*
@ -77,7 +75,8 @@ distribution.
#if defined(DEBUG) #if defined(DEBUG)
# if defined(_MSC_VER) # if defined(_MSC_VER)
# define TIXMLASSERT( x ) if ( !(x)) { __debugbreak(); } //if ( !(x)) WinDebugBreak() # // "(void)0," is for suppressing C4127 warning in "assert(false)", "assert(true)" and the like
# define TIXMLASSERT( x ) if ( !((void)0,(x))) { __debugbreak(); } //if ( !(x)) WinDebugBreak()
# elif defined (ANDROID_NDK) # elif defined (ANDROID_NDK)
# include <android/log.h> # include <android/log.h>
# define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); } # define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); }
@ -90,39 +89,11 @@ distribution.
#endif #endif
#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
// Microsoft visual studio, version 2005 and higher.
/*int _snprintf_s(
char *buffer,
size_t sizeOfBuffer,
size_t count,
const char *format [,
argument] ...
);*/
inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... )
{
va_list va;
va_start( va, format );
int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
va_end( va );
return result;
}
#define TIXML_SSCANF sscanf_s
#elif defined WINCE
#define TIXML_SNPRINTF _snprintf
#define TIXML_SSCANF sscanf
#else
// GCC version 3 and higher
//#warning( "Using sn* functions." )
#define TIXML_SNPRINTF snprintf
#define TIXML_SSCANF sscanf
#endif
/* Versioning, past 1.0.14: /* Versioning, past 1.0.14:
http://semver.org/ http://semver.org/
*/ */
static const int TIXML2_MAJOR_VERSION = 2; static const int TIXML2_MAJOR_VERSION = 3;
static const int TIXML2_MINOR_VERSION = 2; static const int TIXML2_MINOR_VERSION = 0;
static const int TIXML2_PATCH_VERSION = 0; static const int TIXML2_PATCH_VERSION = 0;
namespace tinyxml2 namespace tinyxml2
@ -148,7 +119,7 @@ public:
enum { enum {
NEEDS_ENTITY_PROCESSING = 0x01, NEEDS_ENTITY_PROCESSING = 0x01,
NEEDS_NEWLINE_NORMALIZATION = 0x02, NEEDS_NEWLINE_NORMALIZATION = 0x02,
COLLAPSE_WHITESPACE = 0x04, NEEDS_WHITESPACE_COLLAPSING = 0x04,
TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION, TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
TEXT_ELEMENT_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION, TEXT_ELEMENT_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,
@ -210,13 +181,13 @@ private:
Has a small initial memory pool, so that low or no usage will not Has a small initial memory pool, so that low or no usage will not
cause a call to new/delete cause a call to new/delete
*/ */
template <class T, int INIT> template <class T, int INITIAL_SIZE>
class DynArray class DynArray
{ {
public: public:
DynArray< T, INIT >() { DynArray() {
_mem = _pool; _mem = _pool;
_allocated = INIT; _allocated = INITIAL_SIZE;
_size = 0; _size = 0;
} }
@ -231,11 +202,14 @@ public:
} }
void Push( T t ) { void Push( T t ) {
TIXMLASSERT( _size < INT_MAX );
EnsureCapacity( _size+1 ); EnsureCapacity( _size+1 );
_mem[_size++] = t; _mem[_size++] = t;
} }
T* PushArr( int count ) { T* PushArr( int count ) {
TIXMLASSERT( count >= 0 );
TIXMLASSERT( _size <= INT_MAX - count );
EnsureCapacity( _size+count ); EnsureCapacity( _size+count );
T* ret = &_mem[_size]; T* ret = &_mem[_size];
_size += count; _size += count;
@ -243,6 +217,7 @@ public:
} }
T Pop() { T Pop() {
TIXMLASSERT( _size > 0 );
return _mem[--_size]; return _mem[--_size];
} }
@ -271,24 +246,33 @@ public:
} }
int Size() const { int Size() const {
TIXMLASSERT( _size >= 0 );
return _size; return _size;
} }
int Capacity() const { int Capacity() const {
TIXMLASSERT( _allocated >= INITIAL_SIZE );
return _allocated; return _allocated;
} }
const T* Mem() const { const T* Mem() const {
TIXMLASSERT( _mem );
return _mem; return _mem;
} }
T* Mem() { T* Mem() {
TIXMLASSERT( _mem );
return _mem; return _mem;
} }
private: private:
DynArray( const DynArray& ); // not supported
void operator=( const DynArray& ); // not supported
void EnsureCapacity( int cap ) { void EnsureCapacity( int cap ) {
TIXMLASSERT( cap > 0 );
if ( cap > _allocated ) { if ( cap > _allocated ) {
TIXMLASSERT( cap <= INT_MAX / 2 );
int newAllocated = cap * 2; int newAllocated = cap * 2;
T* newMem = new T[newAllocated]; T* newMem = new T[newAllocated];
memcpy( newMem, _mem, sizeof(T)*_size ); // warning: not using constructors, only works for PODs memcpy( newMem, _mem, sizeof(T)*_size ); // warning: not using constructors, only works for PODs
@ -301,7 +285,7 @@ private:
} }
T* _mem; T* _mem;
T _pool[INIT]; T _pool[INITIAL_SIZE];
int _allocated; // objects allocated int _allocated; // objects allocated
int _size; // number objects in use int _size; // number objects in use
}; };
@ -418,6 +402,9 @@ public:
enum { COUNT = (4*1024)/SIZE }; // Some compilers do not accept to use COUNT in private part if COUNT is private enum { COUNT = (4*1024)/SIZE }; // Some compilers do not accept to use COUNT in private part if COUNT is private
private: private:
MemPoolT( const MemPoolT& ); // not supported
void operator=( const MemPoolT& ); // not supported
union Chunk { union Chunk {
Chunk* next; Chunk* next;
char mem[SIZE]; char mem[SIZE];
@ -531,9 +518,11 @@ class XMLUtil
{ {
public: public:
static const char* SkipWhiteSpace( const char* p ) { static const char* SkipWhiteSpace( const char* p ) {
TIXMLASSERT( p );
while( IsWhiteSpace(*p) ) { while( IsWhiteSpace(*p) ) {
++p; ++p;
} }
TIXMLASSERT( p );
return p; return p;
} }
static char* SkipWhiteSpace( char* p ) { static char* SkipWhiteSpace( char* p ) {
@ -547,9 +536,14 @@ public:
} }
inline static bool IsNameStartChar( unsigned char ch ) { inline static bool IsNameStartChar( unsigned char ch ) {
return ( ( ch < 128 ) ? isalpha( ch ) : 1 ) if ( ch >= 128 ) {
|| ch == ':' // This is a heuristic guess in attempt to not implement Unicode-aware isalpha()
|| ch == '_'; return true;
}
if ( isalpha( ch ) ) {
return true;
}
return ch == ':' || ch == '_';
} }
inline static bool IsNameChar( unsigned char ch ) { inline static bool IsNameChar( unsigned char ch ) {
@ -560,10 +554,10 @@ public:
} }
inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) { inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) {
int n = 0;
if ( p == q ) { if ( p == q ) {
return true; return true;
} }
int n = 0;
while( *p && *q && *p == *q && n<nChar ) { while( *p && *q && *p == *q && n<nChar ) {
++p; ++p;
++q; ++q;
@ -575,7 +569,7 @@ public:
return false; return false;
} }
inline static bool IsUTF8Continuation( const char p ) { inline static bool IsUTF8Continuation( char p ) {
return ( p & 0x80 ) != 0; return ( p & 0x80 ) != 0;
} }
@ -634,10 +628,12 @@ public:
/// Get the XMLDocument that owns this XMLNode. /// Get the XMLDocument that owns this XMLNode.
const XMLDocument* GetDocument() const { const XMLDocument* GetDocument() const {
TIXMLASSERT( _document );
return _document; return _document;
} }
/// Get the XMLDocument that owns this XMLNode. /// Get the XMLDocument that owns this XMLNode.
XMLDocument* GetDocument() { XMLDocument* GetDocument() {
TIXMLASSERT( _document );
return _document; return _document;
} }
@ -687,7 +683,7 @@ public:
/** The meaning of 'value' changes for the specific type. /** The meaning of 'value' changes for the specific type.
@verbatim @verbatim
Document: empty Document: empty (NULL is returned, not an empty string)
Element: name of the element Element: name of the element
Comment: the comment text Comment: the comment text
Unknown: the tag contents Unknown: the tag contents
@ -727,10 +723,10 @@ public:
/** Get the first child element, or optionally the first child /** Get the first child element, or optionally the first child
element with the specified name. element with the specified name.
*/ */
const XMLElement* FirstChildElement( const char* value=0 ) const; const XMLElement* FirstChildElement( const char* name = 0 ) const;
XMLElement* FirstChildElement( const char* value=0 ) { XMLElement* FirstChildElement( const char* name = 0 ) {
return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->FirstChildElement( value )); return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->FirstChildElement( name ));
} }
/// Get the last child node, or null if none exists. /// Get the last child node, or null if none exists.
@ -739,16 +735,16 @@ public:
} }
XMLNode* LastChild() { XMLNode* LastChild() {
return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->LastChild() ); return _lastChild;
} }
/** Get the last child element or optionally the last child /** Get the last child element or optionally the last child
element with the specified name. element with the specified name.
*/ */
const XMLElement* LastChildElement( const char* value=0 ) const; const XMLElement* LastChildElement( const char* name = 0 ) const;
XMLElement* LastChildElement( const char* value=0 ) { XMLElement* LastChildElement( const char* name = 0 ) {
return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->LastChildElement(value) ); return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->LastChildElement(name) );
} }
/// Get the previous (left) sibling node of this node. /// Get the previous (left) sibling node of this node.
@ -761,10 +757,10 @@ public:
} }
/// Get the previous (left) sibling element of this node, with an optionally supplied name. /// Get the previous (left) sibling element of this node, with an optionally supplied name.
const XMLElement* PreviousSiblingElement( const char* value=0 ) const ; const XMLElement* PreviousSiblingElement( const char* name = 0 ) const ;
XMLElement* PreviousSiblingElement( const char* value=0 ) { XMLElement* PreviousSiblingElement( const char* name = 0 ) {
return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->PreviousSiblingElement( value ) ); return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->PreviousSiblingElement( name ) );
} }
/// Get the next (right) sibling node of this node. /// Get the next (right) sibling node of this node.
@ -777,10 +773,10 @@ public:
} }
/// Get the next (right) sibling element of this node, with an optionally supplied name. /// Get the next (right) sibling element of this node, with an optionally supplied name.
const XMLElement* NextSiblingElement( const char* value=0 ) const; const XMLElement* NextSiblingElement( const char* name = 0 ) const;
XMLElement* NextSiblingElement( const char* value=0 ) { XMLElement* NextSiblingElement( const char* name = 0 ) {
return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->NextSiblingElement( value ) ); return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->NextSiblingElement( name ) );
} }
/** /**
@ -866,14 +862,11 @@ public:
*/ */
virtual bool Accept( XMLVisitor* visitor ) const = 0; virtual bool Accept( XMLVisitor* visitor ) const = 0;
// internal
virtual char* ParseDeep( char*, StrPair* );
protected: protected:
XMLNode( XMLDocument* ); XMLNode( XMLDocument* );
virtual ~XMLNode(); virtual ~XMLNode();
XMLNode( const XMLNode& ); // not supported
XMLNode& operator=( const XMLNode& ); // not supported virtual char* ParseDeep( char*, StrPair* );
XMLDocument* _document; XMLDocument* _document;
XMLNode* _parent; XMLNode* _parent;
@ -889,6 +882,10 @@ private:
MemPool* _memPool; MemPool* _memPool;
void Unlink( XMLNode* child ); void Unlink( XMLNode* child );
static void DeleteNode( XMLNode* node ); static void DeleteNode( XMLNode* node );
void InsertChildPreamble( XMLNode* insertThis ) const;
XMLNode( const XMLNode& ); // not supported
XMLNode& operator=( const XMLNode& ); // not supported
}; };
@ -927,18 +924,20 @@ public:
return _isCData; return _isCData;
} }
char* ParseDeep( char*, StrPair* endTag );
virtual XMLNode* ShallowClone( XMLDocument* document ) const; virtual XMLNode* ShallowClone( XMLDocument* document ) const;
virtual bool ShallowEqual( const XMLNode* compare ) const; virtual bool ShallowEqual( const XMLNode* compare ) const;
protected: protected:
XMLText( XMLDocument* doc ) : XMLNode( doc ), _isCData( false ) {} XMLText( XMLDocument* doc ) : XMLNode( doc ), _isCData( false ) {}
virtual ~XMLText() {} virtual ~XMLText() {}
XMLText( const XMLText& ); // not supported
XMLText& operator=( const XMLText& ); // not supported char* ParseDeep( char*, StrPair* endTag );
private: private:
bool _isCData; bool _isCData;
XMLText( const XMLText& ); // not supported
XMLText& operator=( const XMLText& ); // not supported
}; };
@ -956,17 +955,18 @@ public:
virtual bool Accept( XMLVisitor* visitor ) const; virtual bool Accept( XMLVisitor* visitor ) const;
char* ParseDeep( char*, StrPair* endTag );
virtual XMLNode* ShallowClone( XMLDocument* document ) const; virtual XMLNode* ShallowClone( XMLDocument* document ) const;
virtual bool ShallowEqual( const XMLNode* compare ) const; virtual bool ShallowEqual( const XMLNode* compare ) const;
protected: protected:
XMLComment( XMLDocument* doc ); XMLComment( XMLDocument* doc );
virtual ~XMLComment(); virtual ~XMLComment();
XMLComment( const XMLComment& ); // not supported
XMLComment& operator=( const XMLComment& ); // not supported char* ParseDeep( char*, StrPair* endTag );
private: private:
XMLComment( const XMLComment& ); // not supported
XMLComment& operator=( const XMLComment& ); // not supported
}; };
@ -994,13 +994,16 @@ public:
virtual bool Accept( XMLVisitor* visitor ) const; virtual bool Accept( XMLVisitor* visitor ) const;
char* ParseDeep( char*, StrPair* endTag );
virtual XMLNode* ShallowClone( XMLDocument* document ) const; virtual XMLNode* ShallowClone( XMLDocument* document ) const;
virtual bool ShallowEqual( const XMLNode* compare ) const; virtual bool ShallowEqual( const XMLNode* compare ) const;
protected: protected:
XMLDeclaration( XMLDocument* doc ); XMLDeclaration( XMLDocument* doc );
virtual ~XMLDeclaration(); virtual ~XMLDeclaration();
char* ParseDeep( char*, StrPair* endTag );
private:
XMLDeclaration( const XMLDeclaration& ); // not supported XMLDeclaration( const XMLDeclaration& ); // not supported
XMLDeclaration& operator=( const XMLDeclaration& ); // not supported XMLDeclaration& operator=( const XMLDeclaration& ); // not supported
}; };
@ -1026,13 +1029,16 @@ public:
virtual bool Accept( XMLVisitor* visitor ) const; virtual bool Accept( XMLVisitor* visitor ) const;
char* ParseDeep( char*, StrPair* endTag );
virtual XMLNode* ShallowClone( XMLDocument* document ) const; virtual XMLNode* ShallowClone( XMLDocument* document ) const;
virtual bool ShallowEqual( const XMLNode* compare ) const; virtual bool ShallowEqual( const XMLNode* compare ) const;
protected: protected:
XMLUnknown( XMLDocument* doc ); XMLUnknown( XMLDocument* doc );
virtual ~XMLUnknown(); virtual ~XMLUnknown();
char* ParseDeep( char*, StrPair* endTag );
private:
XMLUnknown( const XMLUnknown& ); // not supported XMLUnknown( const XMLUnknown& ); // not supported
XMLUnknown& operator=( const XMLUnknown& ); // not supported XMLUnknown& operator=( const XMLUnknown& ); // not supported
}; };
@ -1481,10 +1487,12 @@ public:
int ClosingType() const { int ClosingType() const {
return _closingType; return _closingType;
} }
char* ParseDeep( char* p, StrPair* endTag );
virtual XMLNode* ShallowClone( XMLDocument* document ) const; virtual XMLNode* ShallowClone( XMLDocument* document ) const;
virtual bool ShallowEqual( const XMLNode* compare ) const; virtual bool ShallowEqual( const XMLNode* compare ) const;
protected:
char* ParseDeep( char* p, StrPair* endTag );
private: private:
XMLElement( XMLDocument* doc ); XMLElement( XMLDocument* doc );
virtual ~XMLElement(); virtual ~XMLElement();
@ -1528,9 +1536,11 @@ public:
~XMLDocument(); ~XMLDocument();
virtual XMLDocument* ToDocument() { virtual XMLDocument* ToDocument() {
TIXMLASSERT( this == _document );
return this; return this;
} }
virtual const XMLDocument* ToDocument() const { virtual const XMLDocument* ToDocument() const {
TIXMLASSERT( this == _document );
return this; return this;
} }
@ -1725,6 +1735,8 @@ private:
MemPoolT< sizeof(XMLComment) > _commentPool; MemPoolT< sizeof(XMLComment) > _commentPool;
static const char* _errorNames[XML_ERROR_COUNT]; static const char* _errorNames[XML_ERROR_COUNT];
void Parse();
}; };
@ -1809,32 +1821,32 @@ public:
return XMLHandle( _node ? _node->FirstChild() : 0 ); return XMLHandle( _node ? _node->FirstChild() : 0 );
} }
/// Get the first child element of this handle. /// Get the first child element of this handle.
XMLHandle FirstChildElement( const char* value=0 ) { XMLHandle FirstChildElement( const char* name = 0 ) {
return XMLHandle( _node ? _node->FirstChildElement( value ) : 0 ); return XMLHandle( _node ? _node->FirstChildElement( name ) : 0 );
} }
/// Get the last child of this handle. /// Get the last child of this handle.
XMLHandle LastChild() { XMLHandle LastChild() {
return XMLHandle( _node ? _node->LastChild() : 0 ); return XMLHandle( _node ? _node->LastChild() : 0 );
} }
/// Get the last child element of this handle. /// Get the last child element of this handle.
XMLHandle LastChildElement( const char* _value=0 ) { XMLHandle LastChildElement( const char* name = 0 ) {
return XMLHandle( _node ? _node->LastChildElement( _value ) : 0 ); return XMLHandle( _node ? _node->LastChildElement( name ) : 0 );
} }
/// Get the previous sibling of this handle. /// Get the previous sibling of this handle.
XMLHandle PreviousSibling() { XMLHandle PreviousSibling() {
return XMLHandle( _node ? _node->PreviousSibling() : 0 ); return XMLHandle( _node ? _node->PreviousSibling() : 0 );
} }
/// Get the previous sibling element of this handle. /// Get the previous sibling element of this handle.
XMLHandle PreviousSiblingElement( const char* _value=0 ) { XMLHandle PreviousSiblingElement( const char* name = 0 ) {
return XMLHandle( _node ? _node->PreviousSiblingElement( _value ) : 0 ); return XMLHandle( _node ? _node->PreviousSiblingElement( name ) : 0 );
} }
/// Get the next sibling of this handle. /// Get the next sibling of this handle.
XMLHandle NextSibling() { XMLHandle NextSibling() {
return XMLHandle( _node ? _node->NextSibling() : 0 ); return XMLHandle( _node ? _node->NextSibling() : 0 );
} }
/// Get the next sibling element of this handle. /// Get the next sibling element of this handle.
XMLHandle NextSiblingElement( const char* _value=0 ) { XMLHandle NextSiblingElement( const char* name = 0 ) {
return XMLHandle( _node ? _node->NextSiblingElement( _value ) : 0 ); return XMLHandle( _node ? _node->NextSiblingElement( name ) : 0 );
} }
/// Safe cast to XMLNode. This can return null. /// Safe cast to XMLNode. This can return null.
@ -1888,26 +1900,26 @@ public:
const XMLConstHandle FirstChild() const { const XMLConstHandle FirstChild() const {
return XMLConstHandle( _node ? _node->FirstChild() : 0 ); return XMLConstHandle( _node ? _node->FirstChild() : 0 );
} }
const XMLConstHandle FirstChildElement( const char* value=0 ) const { const XMLConstHandle FirstChildElement( const char* name = 0 ) const {
return XMLConstHandle( _node ? _node->FirstChildElement( value ) : 0 ); return XMLConstHandle( _node ? _node->FirstChildElement( name ) : 0 );
} }
const XMLConstHandle LastChild() const { const XMLConstHandle LastChild() const {
return XMLConstHandle( _node ? _node->LastChild() : 0 ); return XMLConstHandle( _node ? _node->LastChild() : 0 );
} }
const XMLConstHandle LastChildElement( const char* _value=0 ) const { const XMLConstHandle LastChildElement( const char* name = 0 ) const {
return XMLConstHandle( _node ? _node->LastChildElement( _value ) : 0 ); return XMLConstHandle( _node ? _node->LastChildElement( name ) : 0 );
} }
const XMLConstHandle PreviousSibling() const { const XMLConstHandle PreviousSibling() const {
return XMLConstHandle( _node ? _node->PreviousSibling() : 0 ); return XMLConstHandle( _node ? _node->PreviousSibling() : 0 );
} }
const XMLConstHandle PreviousSiblingElement( const char* _value=0 ) const { const XMLConstHandle PreviousSiblingElement( const char* name = 0 ) const {
return XMLConstHandle( _node ? _node->PreviousSiblingElement( _value ) : 0 ); return XMLConstHandle( _node ? _node->PreviousSiblingElement( name ) : 0 );
} }
const XMLConstHandle NextSibling() const { const XMLConstHandle NextSibling() const {
return XMLConstHandle( _node ? _node->NextSibling() : 0 ); return XMLConstHandle( _node ? _node->NextSibling() : 0 );
} }
const XMLConstHandle NextSiblingElement( const char* _value=0 ) const { const XMLConstHandle NextSiblingElement( const char* name = 0 ) const {
return XMLConstHandle( _node ? _node->NextSiblingElement( _value ) : 0 ); return XMLConstHandle( _node ? _node->NextSiblingElement( name ) : 0 );
} }
@ -2066,7 +2078,7 @@ protected:
virtual void PrintSpace( int depth ); virtual void PrintSpace( int depth );
void Print( const char* format, ... ); void Print( const char* format, ... );
void SealElement(); void SealElementIfJustOpened();
bool _elementJustOpened; bool _elementJustOpened;
DynArray< const char*, 10 > _stack; DynArray< const char*, 10 > _stack;