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.
#if defined(ANDROID_NDK) || defined(__QNXNTO__)
# include <stddef.h>
# include <stdarg.h>
#else
# include <cstddef>
# include <cstdarg>
#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 LF = LINE_FEED;
static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
@ -140,19 +211,19 @@ char* StrPair::ParseName( char* p )
if ( !p || !(*p) ) {
return 0;
}
if ( !XMLUtil::IsNameStartChar( *p ) ) {
return 0;
}
char* const start = p;
while( *p && ( p == start ? XMLUtil::IsNameStartChar( *p ) : XMLUtil::IsNameChar( *p ) )) {
++p;
while ( *p && XMLUtil::IsNameChar( *p ) ) {
++p;
}
if ( p > start ) {
Set( start, p, 0 );
return p;
}
return 0;
}
void StrPair::CollapseWhitespace()
@ -162,7 +233,7 @@ void StrPair::CollapseWhitespace()
// Trim leading space.
_start = XMLUtil::SkipWhiteSpace( _start );
if ( _start && *_start ) {
if ( *_start ) {
char* p = _start; // the read pointer
char* q = _start; // the write pointer
@ -186,6 +257,8 @@ void StrPair::CollapseWhitespace()
const char* StrPair::GetStr()
{
TIXMLASSERT( _start );
TIXMLASSERT( _end );
if ( _flags & NEEDS_FLUSH ) {
*_end = 0;
_flags ^= NEEDS_FLUSH;
@ -226,15 +299,23 @@ const char* StrPair::GetStr()
const int buflen = 10;
char buf[buflen] = { 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( q + len <= p );
TIXMLASSERT( q + len <= adjusted );
p = adjusted;
memcpy( q, buf, len );
q += len;
}
}
else {
int i=0;
for(; i<NUM_ENTITIES; ++i ) {
bool entityFound = false;
for( int i = 0; i < NUM_ENTITIES; ++i ) {
const Entity& entity = entities[i];
if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
&& *( p + entity.length + 1 ) == ';' ) {
@ -242,10 +323,11 @@ const char* StrPair::GetStr()
*q = entity.value;
++q;
p += entity.length + 2;
entityFound = true;
break;
}
}
if ( i == NUM_ENTITIES ) {
if ( !entityFound ) {
// fixme: treat as error?
++p;
++q;
@ -262,11 +344,12 @@ const char* StrPair::GetStr()
}
// The loop below has plenty going on, and this
// is a less useful mode. Break it out.
if ( _flags & COLLAPSE_WHITESPACE ) {
if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
CollapseWhitespace();
}
_flags = (_flags & NEEDS_DELETE);
}
TIXMLASSERT( _start );
return _start;
}
@ -277,6 +360,8 @@ const char* StrPair::GetStr()
const char* XMLUtil::ReadBOM( const char* p, bool* bom )
{
TIXMLASSERT( p );
TIXMLASSERT( bom );
*bom = false;
const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
// Check for BOM:
@ -286,6 +371,7 @@ const char* XMLUtil::ReadBOM( const char* p, bool* bom )
*bom = true;
p += 3;
}
TIXMLASSERT( p );
return p;
}
@ -309,7 +395,7 @@ void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length
*length = 4;
}
else {
*length = 0; // This code won't covert this correctly anyway.
*length = 0; // This code won't convert this correctly anyway.
return;
}
@ -332,8 +418,9 @@ void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length
case 1:
--output;
*output = (char)(input | FIRST_BYTE_MARK[*length]);
default:
break;
default:
TIXMLASSERT( false );
}
}
@ -345,65 +432,83 @@ const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
if ( *(p+1) == '#' && *(p+2) ) {
unsigned long ucs = 0;
TIXMLASSERT( sizeof( ucs ) >= 4 );
ptrdiff_t delta = 0;
unsigned mult = 1;
static const char SEMICOLON = ';';
if ( *(p+2) == 'x' ) {
// Hexadecimal.
if ( !*(p+3) ) {
return 0;
}
const char* q = p+3;
q = strchr( q, ';' );
if ( !q || !*q ) {
if ( !(*q) ) {
return 0;
}
q = strchr( q, SEMICOLON );
if ( !q ) {
return 0;
}
TIXMLASSERT( *q == SEMICOLON );
delta = q-p;
--q;
while ( *q != 'x' ) {
unsigned int digit = 0;
if ( *q >= '0' && *q <= '9' ) {
ucs += mult * (*q - '0');
digit = *q - '0';
}
else if ( *q >= 'a' && *q <= 'f' ) {
ucs += mult * (*q - 'a' + 10);
digit = *q - 'a' + 10;
}
else if ( *q >= 'A' && *q <= 'F' ) {
ucs += mult * (*q - 'A' + 10 );
digit = *q - 'A' + 10;
}
else {
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;
--q;
}
}
else {
// Decimal.
if ( !*(p+2) ) {
return 0;
}
const char* q = p+2;
q = strchr( q, ';' );
if ( !q || !*q ) {
if ( !(*q) ) {
return 0;
}
q = strchr( q, SEMICOLON );
if ( !q ) {
return 0;
}
TIXMLASSERT( *q == SEMICOLON );
delta = q-p;
--q;
while ( *q != '#' ) {
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 {
return 0;
}
TIXMLASSERT( mult <= UINT_MAX / 10 );
mult *= 10;
--q;
}
@ -503,35 +608,31 @@ bool XMLUtil::ToDouble( const char* str, double* value )
char* XMLDocument::Identify( char* p, XMLNode** node )
{
TIXMLASSERT( node );
TIXMLASSERT( p );
char* const start = p;
p = XMLUtil::SkipWhiteSpace( p );
if( !p || !*p ) {
if( !*p ) {
*node = 0;
TIXMLASSERT( p );
return p;
}
// What is this thing?
// These strings define the matching patters:
// These strings define the matching patterns:
static const char* xmlHeader = { "<?" };
static const char* commentHeader = { "<!--" };
static const char* dtdHeader = { "<!" };
static const char* cdataHeader = { "<![CDATA[" };
static const char* dtdHeader = { "<!" };
static const char* elementHeader = { "<" }; // and a header for everything else; check last.
static const int xmlHeaderLen = 2;
static const int commentHeaderLen = 4;
static const int dtdHeaderLen = 2;
static const int cdataHeaderLen = 9;
static const int dtdHeaderLen = 2;
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( XMLDeclaration ) ); // use same memory pool
#if defined(_MSC_VER)
#pragma warning (pop)
#endif
XMLNode* returnNode = 0;
if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
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.
}
TIXMLASSERT( returnNode );
TIXMLASSERT( p );
*node = returnNode;
return p;
}
@ -579,6 +682,7 @@ char* XMLDocument::Identify( char* p, XMLNode** node )
bool XMLDocument::Accept( XMLVisitor* visitor ) const
{
TIXMLASSERT( visitor );
if ( visitor->VisitEnter( *this ) ) {
for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
if ( !node->Accept( visitor ) ) {
@ -612,6 +716,9 @@ XMLNode::~XMLNode()
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();
}
@ -629,6 +736,7 @@ void XMLNode::SetValue( const char* str, bool staticMem )
void XMLNode::DeleteChildren()
{
while( _firstChild ) {
TIXMLASSERT( _lastChild );
TIXMLASSERT( _firstChild->_document == _document );
XMLNode* node = _firstChild;
Unlink( node );
@ -641,7 +749,9 @@ void XMLNode::DeleteChildren()
void XMLNode::Unlink( XMLNode* child )
{
TIXMLASSERT( child );
TIXMLASSERT( child->_document == _document );
TIXMLASSERT( child->_parent == this );
if ( child == _firstChild ) {
_firstChild = _firstChild->_next;
}
@ -661,6 +771,7 @@ void XMLNode::Unlink( XMLNode* child )
void XMLNode::DeleteChild( XMLNode* node )
{
TIXMLASSERT( node );
TIXMLASSERT( node->_document == _document );
TIXMLASSERT( node->_parent == this );
DeleteNode( node );
@ -674,11 +785,7 @@ XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
TIXMLASSERT( false );
return 0;
}
if (addThis->_parent)
addThis->_parent->Unlink( addThis );
else
addThis->_memPool->SetTracked();
InsertChildPreamble( addThis );
if ( _lastChild ) {
TIXMLASSERT( _firstChild );
@ -708,11 +815,7 @@ XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
TIXMLASSERT( false );
return 0;
}
if (addThis->_parent)
addThis->_parent->Unlink( addThis );
else
addThis->_memPool->SetTracked();
InsertChildPreamble( addThis );
if ( _firstChild ) {
TIXMLASSERT( _lastChild );
@ -755,10 +858,7 @@ XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
// The last node or the only node.
return InsertEndChild( addThis );
}
if (addThis->_parent)
addThis->_parent->Unlink( addThis );
else
addThis->_memPool->SetTracked();
InsertChildPreamble( addThis );
addThis->_prev = afterThis;
addThis->_next = afterThis->_next;
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 ) {
XMLElement* element = node->ToElement();
for( const XMLNode* node = _firstChild; node; node = node->_next ) {
const XMLElement* element = node->ToElement();
if ( element ) {
if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {
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 ) {
XMLElement* element = node->ToElement();
for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
const XMLElement* element = node->ToElement();
if ( element ) {
if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {
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();
if ( element
&& (!value || XMLUtil::StringEqual( value, node->Value() ))) {
&& (!name || XMLUtil::StringEqual( name, element->Name() ))) {
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();
if ( element
&& (!value || XMLUtil::StringEqual( value, node->Value() ))) {
&& (!name || XMLUtil::StringEqual( name, element->Name() ))) {
return element;
}
}
@ -847,7 +947,7 @@ char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
XMLNode* node = 0;
p = _document->Identify( p, &node );
if ( p == 0 || node == 0 ) {
if ( node == 0 ) {
break;
}
@ -855,16 +955,27 @@ char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
p = node->ParseDeep( p, &endTag );
if ( !p ) {
DeleteNode( node );
node = 0;
if ( !_document->Error() ) {
_document->SetError( XML_ERROR_PARSING, 0, 0 );
}
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();
if ( ele ) {
// We read the end tag. Return it to the parent.
if ( ele && ele->ClosingType() == XMLElement::CLOSING ) {
if ( ele->ClosingType() == XMLElement::CLOSING ) {
if ( parentEnd ) {
ele->_value.TransferTo( parentEnd );
}
@ -875,31 +986,27 @@ char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
// Handle an end tag returned to this level.
// And handle a bunch of annoying errors.
if ( ele ) {
bool mismatch = false;
if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
if ( endTag.Empty() ) {
if ( ele->ClosingType() == XMLElement::OPEN ) {
mismatch = true;
}
else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
}
else {
if ( ele->ClosingType() != XMLElement::OPEN ) {
mismatch = true;
}
else if ( !endTag.Empty() ) {
if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
mismatch = true;
}
}
if ( mismatch ) {
_document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
p = 0;
}
}
if ( p == 0 ) {
_document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0 );
DeleteNode( node );
node = 0;
break;
}
if ( node ) {
this->InsertEndChild( node );
}
InsertEndChild( node );
}
return 0;
}
@ -914,6 +1021,17 @@ void XMLNode::DeleteNode( XMLNode* 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 ---------- //
char* XMLText::ParseDeep( char* p, StrPair* )
{
@ -928,16 +1046,16 @@ char* XMLText::ParseDeep( char* p, StrPair* )
else {
int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
flags |= StrPair::COLLAPSE_WHITESPACE;
flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
}
p = _value.ParseText( p, "<", flags );
if ( !p ) {
_document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
}
if ( p && *p ) {
return p-1;
}
if ( !p ) {
_document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
}
}
return 0;
}
@ -1138,7 +1256,7 @@ char* XMLAttribute::ParseDeep( char* p, bool processEntities )
// Skip white space before =
p = XMLUtil::SkipWhiteSpace( p );
if ( !p || *p != '=' ) {
if ( *p != '=' ) {
return 0;
}
@ -1474,7 +1592,7 @@ char* XMLElement::ParseAttributes( char* p )
// Read the attributes.
while( p ) {
p = XMLUtil::SkipWhiteSpace( p );
if ( !p || !(*p) ) {
if ( !(*p) ) {
_document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
return 0;
}
@ -1506,15 +1624,15 @@ char* XMLElement::ParseAttributes( char* p )
prevAttribute = attrib;
}
// end of the tag
else if ( *p == '/' && *(p+1) == '>' ) {
_closingType = CLOSED;
return p+2; // done; sealed element.
}
// end of the tag
else if ( *p == '>' ) {
++p;
break;
}
// end of the tag
else if ( *p == '/' && *(p+1) == '>' ) {
_closingType = CLOSED;
return p+2; // done; sealed element.
}
else {
_document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
return 0;
@ -1541,9 +1659,6 @@ char* XMLElement::ParseDeep( char* p, StrPair* strPair )
{
// Read the element name.
p = XMLUtil::SkipWhiteSpace( p );
if ( !p ) {
return 0;
}
// The closing element is the </element> form. It is
// parsed just like a regular element then deleted from
@ -1586,7 +1701,7 @@ bool XMLElement::ShallowEqual( const XMLNode* compare ) const
{
TIXMLASSERT( compare );
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* b=other->FirstAttribute();
@ -1659,7 +1774,8 @@ XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
_errorStr2( 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;
}
const size_t size = filelength;
if ( size == 0 ) {
if ( (unsigned long)filelength >= (size_t)-1 ) {
// 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 );
return _errorID;
}
const size_t size = filelength;
_charBuffer = new char[size+1];
size_t read = fread( _charBuffer, 1, size, fp );
if ( read != size ) {
@ -1831,15 +1953,7 @@ XMLError XMLDocument::LoadFile( FILE* fp )
_charBuffer[size] = 0;
const char* p = _charBuffer;
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 );
Parse();
return _errorID;
}
@ -1859,6 +1973,9 @@ XMLError XMLDocument::SaveFile( const char* filename, 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 );
Print( &stream );
return _errorID;
@ -1867,7 +1984,6 @@ XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
XMLError XMLDocument::Parse( const char* p, size_t len )
{
const char* start = p;
Clear();
if ( len == 0 || !p || !*p ) {
@ -1881,15 +1997,7 @@ XMLError XMLDocument::Parse( const char* p, size_t len )
memcpy( _charBuffer, p, len );
_charBuffer[len] = 0;
p = XMLUtil::SkipWhiteSpace( p );
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 );
Parse();
if ( Error() ) {
// clean up now essentially dangling memory.
// 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
{
XMLPrinter stdStreamer( stdout );
if ( !streamer ) {
streamer = &stdStreamer;
}
if ( streamer ) {
Accept( streamer );
}
else {
XMLPrinter stdoutStreamer( stdout );
Accept( &stdoutStreamer );
}
}
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
{
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
@ -1942,11 +2054,27 @@ void XMLDocument::PrintError() const
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",
_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 ) :
_elementJustOpened( false ),
@ -1962,16 +2090,13 @@ XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
_restrictedEntityFlag[i] = false;
}
for( int i=0; i<NUM_ENTITIES; ++i ) {
TIXMLASSERT( entities[i].value < ENTITY_RANGE );
if ( entities[i].value < ENTITY_RANGE ) {
_entityFlag[ (int)entities[i].value ] = true;
const char entityValue = entities[i].value;
TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
_entityFlag[ (unsigned char)entityValue ] = true;
}
}
// Clang doesn't like indexing arrays with 'char'
// so cast to int. (Looks strange.)
_restrictedEntityFlag[(int)'&'] = true;
_restrictedEntityFlag[(int)'<'] = true;
_restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
_restrictedEntityFlag[(unsigned char)'&'] = true;
_restrictedEntityFlag[(unsigned char)'<'] = true;
_restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
_buffer.Push( 0 );
}
@ -1985,34 +2110,14 @@ void XMLPrinter::Print( const char* format, ... )
vfprintf( _fp, format, va );
}
else {
#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
#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
const int len = TIXML_VSCPRINTF( format, va );
// Close out and re-start the va-args
va_end( va );
TIXMLASSERT( len >= 0 );
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.
#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
#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
TIXML_VSNPRINTF( p, len+1, format, 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.
const char* q = p;
const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
if ( _processEntities ) {
const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
while ( *q ) {
TIXMLASSERT( p <= q );
// Remember, char is sometimes signed. (How many times has that bitten me?)
if ( *q > 0 && *q < ENTITY_RANGE ) {
// Check for entities. If one is found, flush
// the stream up until the entity, write the
// entity, and keep looking.
if ( flag[(unsigned)(*q)] ) {
if ( flag[(unsigned char)(*q)] ) {
while ( p < q ) {
Print( "%c", *p );
++p;
const size_t delta = q - 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 ) {
if ( entities[i].value == *q ) {
Print( "&%s;", entities[i].pattern );
entityPatternPrinted = true;
break;
}
}
if ( !entityPatternPrinted ) {
// TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
TIXMLASSERT( false );
}
++p;
}
}
++q;
TIXMLASSERT( p <= q );
}
}
// Flush the remaining string. This will be the entire
// string if an entity wasn't found.
if ( !_processEntities || (q-p > 0) ) {
TIXMLASSERT( p <= q );
if ( !_processEntities || ( p < q ) ) {
Print( "%s", p );
}
}
@ -2078,9 +2195,7 @@ void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
void XMLPrinter::OpenElement( const char* name, bool compactMode )
{
if ( _elementJustOpened ) {
SealElement();
}
SealElementIfJustOpened();
_stack.Push( name );
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;
Print( ">" );
}
@ -2175,13 +2293,9 @@ void XMLPrinter::PushText( const char* text, bool cdata )
{
_textDepth = _depth-1;
if ( _elementJustOpened ) {
SealElement();
}
SealElementIfJustOpened();
if ( cdata ) {
Print( "<![CDATA[" );
Print( "%s", text );
Print( "]]>" );
Print( "<![CDATA[%s]]>", text );
}
else {
PrintString( text, true );
@ -2230,9 +2344,7 @@ void XMLPrinter::PushText( double value )
void XMLPrinter::PushComment( const char* comment )
{
if ( _elementJustOpened ) {
SealElement();
}
SealElementIfJustOpened();
if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Print( "\n" );
PrintSpace( _depth );
@ -2244,9 +2356,7 @@ void XMLPrinter::PushComment( const char* comment )
void XMLPrinter::PushDeclaration( const char* value )
{
if ( _elementJustOpened ) {
SealElement();
}
SealElementIfJustOpened();
if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Print( "\n" );
PrintSpace( _depth );
@ -2258,9 +2368,7 @@ void XMLPrinter::PushDeclaration( const char* value )
void XMLPrinter::PushUnknown( const char* value )
{
if ( _elementJustOpened ) {
SealElement();
}
SealElementIfJustOpened();
if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Print( "\n" );
PrintSpace( _depth );
@ -2282,8 +2390,11 @@ bool XMLPrinter::VisitEnter( const XMLDocument& doc )
bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
{
const XMLElement* parentElem = element.Parent()->ToElement();
bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
const XMLElement* parentElem = 0;
if ( element.Parent() ) {
parentElem = element.Parent()->ToElement();
}
const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
OpenElement( element.Name(), compactMode );
while ( attribute ) {
PushAttribute( attribute->Name(), attribute->Value() );

View File

@ -30,14 +30,12 @@ distribution.
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <stdarg.h>
#else
# include <cctype>
# include <climits>
# include <cstdio>
# include <cstdlib>
# include <cstring>
# include <cstdarg>
#endif
/*
@ -77,7 +75,8 @@ distribution.
#if defined(DEBUG)
# 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)
# include <android/log.h>
# define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); }
@ -90,39 +89,11 @@ distribution.
#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:
http://semver.org/
*/
static const int TIXML2_MAJOR_VERSION = 2;
static const int TIXML2_MINOR_VERSION = 2;
static const int TIXML2_MAJOR_VERSION = 3;
static const int TIXML2_MINOR_VERSION = 0;
static const int TIXML2_PATCH_VERSION = 0;
namespace tinyxml2
@ -148,7 +119,7 @@ public:
enum {
NEEDS_ENTITY_PROCESSING = 0x01,
NEEDS_NEWLINE_NORMALIZATION = 0x02,
COLLAPSE_WHITESPACE = 0x04,
NEEDS_WHITESPACE_COLLAPSING = 0x04,
TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | 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
cause a call to new/delete
*/
template <class T, int INIT>
template <class T, int INITIAL_SIZE>
class DynArray
{
public:
DynArray< T, INIT >() {
DynArray() {
_mem = _pool;
_allocated = INIT;
_allocated = INITIAL_SIZE;
_size = 0;
}
@ -231,11 +202,14 @@ public:
}
void Push( T t ) {
TIXMLASSERT( _size < INT_MAX );
EnsureCapacity( _size+1 );
_mem[_size++] = t;
}
T* PushArr( int count ) {
TIXMLASSERT( count >= 0 );
TIXMLASSERT( _size <= INT_MAX - count );
EnsureCapacity( _size+count );
T* ret = &_mem[_size];
_size += count;
@ -243,6 +217,7 @@ public:
}
T Pop() {
TIXMLASSERT( _size > 0 );
return _mem[--_size];
}
@ -271,24 +246,33 @@ public:
}
int Size() const {
TIXMLASSERT( _size >= 0 );
return _size;
}
int Capacity() const {
TIXMLASSERT( _allocated >= INITIAL_SIZE );
return _allocated;
}
const T* Mem() const {
TIXMLASSERT( _mem );
return _mem;
}
T* Mem() {
TIXMLASSERT( _mem );
return _mem;
}
private:
DynArray( const DynArray& ); // not supported
void operator=( const DynArray& ); // not supported
void EnsureCapacity( int cap ) {
TIXMLASSERT( cap > 0 );
if ( cap > _allocated ) {
TIXMLASSERT( cap <= INT_MAX / 2 );
int newAllocated = cap * 2;
T* newMem = new T[newAllocated];
memcpy( newMem, _mem, sizeof(T)*_size ); // warning: not using constructors, only works for PODs
@ -301,7 +285,7 @@ private:
}
T* _mem;
T _pool[INIT];
T _pool[INITIAL_SIZE];
int _allocated; // objects allocated
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
private:
MemPoolT( const MemPoolT& ); // not supported
void operator=( const MemPoolT& ); // not supported
union Chunk {
Chunk* next;
char mem[SIZE];
@ -531,9 +518,11 @@ class XMLUtil
{
public:
static const char* SkipWhiteSpace( const char* p ) {
TIXMLASSERT( p );
while( IsWhiteSpace(*p) ) {
++p;
}
TIXMLASSERT( p );
return p;
}
static char* SkipWhiteSpace( char* p ) {
@ -547,9 +536,14 @@ public:
}
inline static bool IsNameStartChar( unsigned char ch ) {
return ( ( ch < 128 ) ? isalpha( ch ) : 1 )
|| ch == ':'
|| ch == '_';
if ( ch >= 128 ) {
// This is a heuristic guess in attempt to not implement Unicode-aware isalpha()
return true;
}
if ( isalpha( ch ) ) {
return true;
}
return ch == ':' || 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 ) {
int n = 0;
if ( p == q ) {
return true;
}
int n = 0;
while( *p && *q && *p == *q && n<nChar ) {
++p;
++q;
@ -575,7 +569,7 @@ public:
return false;
}
inline static bool IsUTF8Continuation( const char p ) {
inline static bool IsUTF8Continuation( char p ) {
return ( p & 0x80 ) != 0;
}
@ -634,10 +628,12 @@ public:
/// Get the XMLDocument that owns this XMLNode.
const XMLDocument* GetDocument() const {
TIXMLASSERT( _document );
return _document;
}
/// Get the XMLDocument that owns this XMLNode.
XMLDocument* GetDocument() {
TIXMLASSERT( _document );
return _document;
}
@ -687,7 +683,7 @@ public:
/** The meaning of 'value' changes for the specific type.
@verbatim
Document: empty
Document: empty (NULL is returned, not an empty string)
Element: name of the element
Comment: the comment text
Unknown: the tag contents
@ -727,10 +723,10 @@ public:
/** Get the first child element, or optionally the first child
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 ) {
return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->FirstChildElement( value ));
XMLElement* FirstChildElement( const char* name = 0 ) {
return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->FirstChildElement( name ));
}
/// Get the last child node, or null if none exists.
@ -739,16 +735,16 @@ public:
}
XMLNode* LastChild() {
return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->LastChild() );
return _lastChild;
}
/** Get the last child element or optionally the last child
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 ) {
return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->LastChildElement(value) );
XMLElement* LastChildElement( const char* name = 0 ) {
return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->LastChildElement(name) );
}
/// 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.
const XMLElement* PreviousSiblingElement( const char* value=0 ) const ;
const XMLElement* PreviousSiblingElement( const char* name = 0 ) const ;
XMLElement* PreviousSiblingElement( const char* value=0 ) {
return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->PreviousSiblingElement( value ) );
XMLElement* PreviousSiblingElement( const char* name = 0 ) {
return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->PreviousSiblingElement( name ) );
}
/// 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.
const XMLElement* NextSiblingElement( const char* value=0 ) const;
const XMLElement* NextSiblingElement( const char* name = 0 ) const;
XMLElement* NextSiblingElement( const char* value=0 ) {
return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->NextSiblingElement( value ) );
XMLElement* NextSiblingElement( const char* name = 0 ) {
return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->NextSiblingElement( name ) );
}
/**
@ -866,14 +862,11 @@ public:
*/
virtual bool Accept( XMLVisitor* visitor ) const = 0;
// internal
virtual char* ParseDeep( char*, StrPair* );
protected:
XMLNode( XMLDocument* );
virtual ~XMLNode();
XMLNode( const XMLNode& ); // not supported
XMLNode& operator=( const XMLNode& ); // not supported
virtual char* ParseDeep( char*, StrPair* );
XMLDocument* _document;
XMLNode* _parent;
@ -889,6 +882,10 @@ private:
MemPool* _memPool;
void Unlink( XMLNode* child );
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;
}
char* ParseDeep( char*, StrPair* endTag );
virtual XMLNode* ShallowClone( XMLDocument* document ) const;
virtual bool ShallowEqual( const XMLNode* compare ) const;
protected:
XMLText( XMLDocument* doc ) : XMLNode( doc ), _isCData( false ) {}
virtual ~XMLText() {}
XMLText( const XMLText& ); // not supported
XMLText& operator=( const XMLText& ); // not supported
char* ParseDeep( char*, StrPair* endTag );
private:
bool _isCData;
XMLText( const XMLText& ); // not supported
XMLText& operator=( const XMLText& ); // not supported
};
@ -956,17 +955,18 @@ public:
virtual bool Accept( XMLVisitor* visitor ) const;
char* ParseDeep( char*, StrPair* endTag );
virtual XMLNode* ShallowClone( XMLDocument* document ) const;
virtual bool ShallowEqual( const XMLNode* compare ) const;
protected:
XMLComment( XMLDocument* doc );
virtual ~XMLComment();
XMLComment( const XMLComment& ); // not supported
XMLComment& operator=( const XMLComment& ); // not supported
char* ParseDeep( char*, StrPair* endTag );
private:
XMLComment( const XMLComment& ); // not supported
XMLComment& operator=( const XMLComment& ); // not supported
};
@ -994,13 +994,16 @@ public:
virtual bool Accept( XMLVisitor* visitor ) const;
char* ParseDeep( char*, StrPair* endTag );
virtual XMLNode* ShallowClone( XMLDocument* document ) const;
virtual bool ShallowEqual( const XMLNode* compare ) const;
protected:
XMLDeclaration( XMLDocument* doc );
virtual ~XMLDeclaration();
char* ParseDeep( char*, StrPair* endTag );
private:
XMLDeclaration( const XMLDeclaration& ); // not supported
XMLDeclaration& operator=( const XMLDeclaration& ); // not supported
};
@ -1026,13 +1029,16 @@ public:
virtual bool Accept( XMLVisitor* visitor ) const;
char* ParseDeep( char*, StrPair* endTag );
virtual XMLNode* ShallowClone( XMLDocument* document ) const;
virtual bool ShallowEqual( const XMLNode* compare ) const;
protected:
XMLUnknown( XMLDocument* doc );
virtual ~XMLUnknown();
char* ParseDeep( char*, StrPair* endTag );
private:
XMLUnknown( const XMLUnknown& ); // not supported
XMLUnknown& operator=( const XMLUnknown& ); // not supported
};
@ -1481,10 +1487,12 @@ public:
int ClosingType() const {
return _closingType;
}
char* ParseDeep( char* p, StrPair* endTag );
virtual XMLNode* ShallowClone( XMLDocument* document ) const;
virtual bool ShallowEqual( const XMLNode* compare ) const;
protected:
char* ParseDeep( char* p, StrPair* endTag );
private:
XMLElement( XMLDocument* doc );
virtual ~XMLElement();
@ -1528,9 +1536,11 @@ public:
~XMLDocument();
virtual XMLDocument* ToDocument() {
TIXMLASSERT( this == _document );
return this;
}
virtual const XMLDocument* ToDocument() const {
TIXMLASSERT( this == _document );
return this;
}
@ -1725,6 +1735,8 @@ private:
MemPoolT< sizeof(XMLComment) > _commentPool;
static const char* _errorNames[XML_ERROR_COUNT];
void Parse();
};
@ -1809,32 +1821,32 @@ public:
return XMLHandle( _node ? _node->FirstChild() : 0 );
}
/// Get the first child element of this handle.
XMLHandle FirstChildElement( const char* value=0 ) {
return XMLHandle( _node ? _node->FirstChildElement( value ) : 0 );
XMLHandle FirstChildElement( const char* name = 0 ) {
return XMLHandle( _node ? _node->FirstChildElement( name ) : 0 );
}
/// Get the last child of this handle.
XMLHandle LastChild() {
return XMLHandle( _node ? _node->LastChild() : 0 );
}
/// Get the last child element of this handle.
XMLHandle LastChildElement( const char* _value=0 ) {
return XMLHandle( _node ? _node->LastChildElement( _value ) : 0 );
XMLHandle LastChildElement( const char* name = 0 ) {
return XMLHandle( _node ? _node->LastChildElement( name ) : 0 );
}
/// Get the previous sibling of this handle.
XMLHandle PreviousSibling() {
return XMLHandle( _node ? _node->PreviousSibling() : 0 );
}
/// Get the previous sibling element of this handle.
XMLHandle PreviousSiblingElement( const char* _value=0 ) {
return XMLHandle( _node ? _node->PreviousSiblingElement( _value ) : 0 );
XMLHandle PreviousSiblingElement( const char* name = 0 ) {
return XMLHandle( _node ? _node->PreviousSiblingElement( name ) : 0 );
}
/// Get the next sibling of this handle.
XMLHandle NextSibling() {
return XMLHandle( _node ? _node->NextSibling() : 0 );
}
/// Get the next sibling element of this handle.
XMLHandle NextSiblingElement( const char* _value=0 ) {
return XMLHandle( _node ? _node->NextSiblingElement( _value ) : 0 );
XMLHandle NextSiblingElement( const char* name = 0 ) {
return XMLHandle( _node ? _node->NextSiblingElement( name ) : 0 );
}
/// Safe cast to XMLNode. This can return null.
@ -1888,26 +1900,26 @@ public:
const XMLConstHandle FirstChild() const {
return XMLConstHandle( _node ? _node->FirstChild() : 0 );
}
const XMLConstHandle FirstChildElement( const char* value=0 ) const {
return XMLConstHandle( _node ? _node->FirstChildElement( value ) : 0 );
const XMLConstHandle FirstChildElement( const char* name = 0 ) const {
return XMLConstHandle( _node ? _node->FirstChildElement( name ) : 0 );
}
const XMLConstHandle LastChild() const {
return XMLConstHandle( _node ? _node->LastChild() : 0 );
}
const XMLConstHandle LastChildElement( const char* _value=0 ) const {
return XMLConstHandle( _node ? _node->LastChildElement( _value ) : 0 );
const XMLConstHandle LastChildElement( const char* name = 0 ) const {
return XMLConstHandle( _node ? _node->LastChildElement( name ) : 0 );
}
const XMLConstHandle PreviousSibling() const {
return XMLConstHandle( _node ? _node->PreviousSibling() : 0 );
}
const XMLConstHandle PreviousSiblingElement( const char* _value=0 ) const {
return XMLConstHandle( _node ? _node->PreviousSiblingElement( _value ) : 0 );
const XMLConstHandle PreviousSiblingElement( const char* name = 0 ) const {
return XMLConstHandle( _node ? _node->PreviousSiblingElement( name ) : 0 );
}
const XMLConstHandle NextSibling() const {
return XMLConstHandle( _node ? _node->NextSibling() : 0 );
}
const XMLConstHandle NextSiblingElement( const char* _value=0 ) const {
return XMLConstHandle( _node ? _node->NextSiblingElement( _value ) : 0 );
const XMLConstHandle NextSiblingElement( const char* name = 0 ) const {
return XMLConstHandle( _node ? _node->NextSiblingElement( name ) : 0 );
}
@ -2066,7 +2078,7 @@ protected:
virtual void PrintSpace( int depth );
void Print( const char* format, ... );
void SealElement();
void SealElementIfJustOpened();
bool _elementJustOpened;
DynArray< const char*, 10 > _stack;