parent
e71ab70356
commit
fc19c6ca11
|
@ -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() );
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue