Updated TinyXML and simplecpp

This commit is contained in:
PKEuS 2016-12-29 11:28:25 +01:00
parent 24332b540d
commit b86a39d38a
3 changed files with 536 additions and 226 deletions

View File

@ -73,7 +73,7 @@ namespace {
long long stringToLL(const std::string &s) long long stringToLL(const std::string &s)
{ {
long long ret; long long ret;
bool hex = (s.compare(0, 2, "0x") == 0); const bool hex = (s.length()>2 && s.compare(0, 2, "0x") == 0);
std::istringstream istr(hex ? s.substr(2) : s); std::istringstream istr(hex ? s.substr(2) : s);
if (hex) if (hex)
istr >> std::hex; istr >> std::hex;
@ -84,7 +84,7 @@ namespace {
unsigned long long stringToULL(const std::string &s) unsigned long long stringToULL(const std::string &s)
{ {
unsigned long long ret; unsigned long long ret;
bool hex = (s.compare(0, 2, "0x") == 0); const bool hex = (s.length()>2 && s.compare(0, 2, "0x") == 0);
std::istringstream istr(hex ? s.substr(2) : s); std::istringstream istr(hex ? s.substr(2) : s);
if (hex) if (hex)
istr >> std::hex; istr >> std::hex;
@ -504,11 +504,11 @@ void simplecpp::TokenList::readfile(std::istream &istr, const std::string &filen
if (ch == '\"' && cback() && cback()->op == 'R') { if (ch == '\"' && cback() && cback()->op == 'R') {
std::string delim; std::string delim;
ch = readChar(istr,bom); ch = readChar(istr,bom);
while (istr.good() && ch != '(' && ch != '\"' && ch != '\n') { while (istr.good() && ch != '(' && ch != '\n') {
delim += ch; delim += ch;
ch = readChar(istr,bom); ch = readChar(istr,bom);
} }
if (!istr.good() || ch == '\"' || ch == '\n') if (!istr.good() || ch == '\n')
// TODO report // TODO report
return; return;
currentToken = '\"'; currentToken = '\"';

View File

@ -149,6 +149,7 @@ void StrPair::TransferTo( StrPair* other )
// This in effect implements the assignment operator by "moving" // This in effect implements the assignment operator by "moving"
// ownership (as in auto_ptr). // ownership (as in auto_ptr).
TIXMLASSERT( other != 0 );
TIXMLASSERT( other->_flags == 0 ); TIXMLASSERT( other->_flags == 0 );
TIXMLASSERT( other->_start == 0 ); TIXMLASSERT( other->_start == 0 );
TIXMLASSERT( other->_end == 0 ); TIXMLASSERT( other->_end == 0 );
@ -188,9 +189,11 @@ void StrPair::SetStr( const char* str, int flags )
} }
char* StrPair::ParseText( char* p, const char* endTag, int strFlags ) char* StrPair::ParseText( char* p, const char* endTag, int strFlags, int* curLineNumPtr )
{ {
TIXMLASSERT( p );
TIXMLASSERT( endTag && *endTag ); TIXMLASSERT( endTag && *endTag );
TIXMLASSERT(curLineNumPtr);
char* start = p; char* start = p;
char endChar = *endTag; char endChar = *endTag;
@ -201,8 +204,11 @@ char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) { if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
Set( start, p, strFlags ); Set( start, p, strFlags );
return p + length; return p + length;
} else if (*p == '\n') {
++(*curLineNumPtr);
} }
++p; ++p;
TIXMLASSERT( p );
} }
return 0; return 0;
} }
@ -233,15 +239,15 @@ void StrPair::CollapseWhitespace()
// Adjusting _start would cause undefined behavior on delete[] // Adjusting _start would cause undefined behavior on delete[]
TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 ); TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
// Trim leading space. // Trim leading space.
_start = XMLUtil::SkipWhiteSpace( _start ); _start = XMLUtil::SkipWhiteSpace( _start, 0 );
if ( *_start ) { if ( *_start ) {
char* p = _start; // the read pointer const char* p = _start; // the read pointer
char* q = _start; // the write pointer char* q = _start; // the write pointer
while( *p ) { while( *p ) {
if ( XMLUtil::IsWhiteSpace( *p )) { if ( XMLUtil::IsWhiteSpace( *p )) {
p = XMLUtil::SkipWhiteSpace( p ); p = XMLUtil::SkipWhiteSpace( p, 0 );
if ( *p == 0 ) { if ( *p == 0 ) {
break; // don't write to q; this trims the trailing space. break; // don't write to q; this trims the trailing space.
} }
@ -266,7 +272,7 @@ const char* StrPair::GetStr()
_flags ^= NEEDS_FLUSH; _flags ^= NEEDS_FLUSH;
if ( _flags ) { if ( _flags ) {
char* p = _start; // the read pointer const char* p = _start; // the read pointer
char* q = _start; // the write pointer char* q = _start; // the write pointer
while( p < _end ) { while( p < _end ) {
@ -280,7 +286,8 @@ const char* StrPair::GetStr()
else { else {
++p; ++p;
} }
*q++ = LF; *q = LF;
++q;
} }
else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) { else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
if ( *(p+1) == CR ) { if ( *(p+1) == CR ) {
@ -289,7 +296,8 @@ const char* StrPair::GetStr()
else { else {
++p; ++p;
} }
*q++ = LF; *q = LF;
++q;
} }
else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) { else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
// Entities handled by tinyXML2: // Entities handled by tinyXML2:
@ -537,7 +545,7 @@ void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
void XMLUtil::ToStr( bool v, char* buffer, int bufferSize ) void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
{ {
TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 ); TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? "true" : "false" );
} }
/* /*
@ -556,6 +564,13 @@ void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
} }
void XMLUtil::ToStr(int64_t v, char* buffer, int bufferSize)
{
// horrible syntax trick to make the compiler happy about %lld
TIXML_SNPRINTF(buffer, bufferSize, "%lld", (long long)v);
}
bool XMLUtil::ToInt( const char* str, int* value ) bool XMLUtil::ToInt( const char* str, int* value )
{ {
if ( TIXML_SSCANF( str, "%d", value ) == 1 ) { if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
@ -599,6 +614,7 @@ bool XMLUtil::ToFloat( const char* str, float* value )
return false; return false;
} }
bool XMLUtil::ToDouble( const char* str, double* value ) bool XMLUtil::ToDouble( const char* str, double* value )
{ {
if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) { if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
@ -608,12 +624,24 @@ bool XMLUtil::ToDouble( const char* str, double* value )
} }
bool XMLUtil::ToInt64(const char* str, int64_t* value)
{
long long v = 0; // horrible syntax trick to make the compiler happy about %lld
if (TIXML_SSCANF(str, "%lld", &v) == 1) {
*value = (int64_t)v;
return true;
}
return false;
}
char* XMLDocument::Identify( char* p, XMLNode** node ) char* XMLDocument::Identify( char* p, XMLNode** node )
{ {
TIXMLASSERT( node ); TIXMLASSERT( node );
TIXMLASSERT( p ); TIXMLASSERT( p );
char* const start = p; char* const start = p;
p = XMLUtil::SkipWhiteSpace( p ); int const startLine = _parseCurLineNum;
p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
if( !*p ) { if( !*p ) {
*node = 0; *node = 0;
TIXMLASSERT( p ); TIXMLASSERT( p );
@ -639,12 +667,14 @@ char* XMLDocument::Identify( char* p, XMLNode** node )
if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) { if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() ); TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
returnNode = new (_commentPool.Alloc()) XMLDeclaration( this ); returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
returnNode->_parseLineNum = _parseCurLineNum;
returnNode->_memPool = &_commentPool; returnNode->_memPool = &_commentPool;
p += xmlHeaderLen; p += xmlHeaderLen;
} }
else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) { else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() ); TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
returnNode = new (_commentPool.Alloc()) XMLComment( this ); returnNode = new (_commentPool.Alloc()) XMLComment( this );
returnNode->_parseLineNum = _parseCurLineNum;
returnNode->_memPool = &_commentPool; returnNode->_memPool = &_commentPool;
p += commentHeaderLen; p += commentHeaderLen;
} }
@ -652,6 +682,7 @@ char* XMLDocument::Identify( char* p, XMLNode** node )
TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() ); TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
XMLText* text = new (_textPool.Alloc()) XMLText( this ); XMLText* text = new (_textPool.Alloc()) XMLText( this );
returnNode = text; returnNode = text;
returnNode->_parseLineNum = _parseCurLineNum;
returnNode->_memPool = &_textPool; returnNode->_memPool = &_textPool;
p += cdataHeaderLen; p += cdataHeaderLen;
text->SetCData( true ); text->SetCData( true );
@ -659,12 +690,14 @@ char* XMLDocument::Identify( char* p, XMLNode** node )
else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) { else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() ); TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
returnNode = new (_commentPool.Alloc()) XMLUnknown( this ); returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
returnNode->_parseLineNum = _parseCurLineNum;
returnNode->_memPool = &_commentPool; returnNode->_memPool = &_commentPool;
p += dtdHeaderLen; p += dtdHeaderLen;
} }
else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) { else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() ); TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
returnNode = new (_elementPool.Alloc()) XMLElement( this ); returnNode = new (_elementPool.Alloc()) XMLElement( this );
returnNode->_parseLineNum = _parseCurLineNum;
returnNode->_memPool = &_elementPool; returnNode->_memPool = &_elementPool;
p += elementHeaderLen; p += elementHeaderLen;
} }
@ -672,7 +705,9 @@ char* XMLDocument::Identify( char* p, XMLNode** node )
TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() ); TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
returnNode = new (_textPool.Alloc()) XMLText( this ); returnNode = new (_textPool.Alloc()) XMLText( this );
returnNode->_memPool = &_textPool; returnNode->_memPool = &_textPool;
returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character
p = start; // Back it up, all the text counts. p = start; // Back it up, all the text counts.
_parseCurLineNum = startLine;
} }
TIXMLASSERT( returnNode ); TIXMLASSERT( returnNode );
@ -701,8 +736,10 @@ bool XMLDocument::Accept( XMLVisitor* visitor ) const
XMLNode::XMLNode( XMLDocument* doc ) : XMLNode::XMLNode( XMLDocument* doc ) :
_document( doc ), _document( doc ),
_parent( 0 ), _parent( 0 ),
_parseLineNum( 0 ),
_firstChild( 0 ), _lastChild( 0 ), _firstChild( 0 ), _lastChild( 0 ),
_prev( 0 ), _next( 0 ), _prev( 0 ), _next( 0 ),
_userData( 0 ),
_memPool( 0 ) _memPool( 0 )
{ {
} }
@ -718,7 +755,7 @@ XMLNode::~XMLNode()
const char* XMLNode::Value() const const char* XMLNode::Value() const
{ {
// Catch an edge case: XMLDocuments don't have a a Value. Carefully return nullptr. // Edge case: XMLDocuments don't have a Value. Return null.
if ( this->ToDocument() ) if ( this->ToDocument() )
return 0; return 0;
return _value.GetStr(); return _value.GetStr();
@ -739,11 +776,7 @@ void XMLNode::DeleteChildren()
{ {
while( _firstChild ) { while( _firstChild ) {
TIXMLASSERT( _lastChild ); TIXMLASSERT( _lastChild );
TIXMLASSERT( _firstChild->_document == _document ); DeleteChild( _firstChild );
XMLNode* node = _firstChild;
Unlink( node );
DeleteNode( node );
} }
_firstChild = _lastChild = 0; _firstChild = _lastChild = 0;
} }
@ -876,11 +909,9 @@ XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
const XMLElement* XMLNode::FirstChildElement( const char* name ) const const XMLElement* XMLNode::FirstChildElement( const char* name ) const
{ {
for( const XMLNode* node = _firstChild; node; node = node->_next ) { for( const XMLNode* node = _firstChild; node; node = node->_next ) {
const XMLElement* element = node->ToElement(); const XMLElement* element = node->ToElementWithName( name );
if ( element ) { if ( element ) {
if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) { return element;
return element;
}
} }
} }
return 0; return 0;
@ -890,11 +921,9 @@ const XMLElement* XMLNode::FirstChildElement( const char* name ) const
const XMLElement* XMLNode::LastChildElement( const char* name ) const const XMLElement* XMLNode::LastChildElement( const char* name ) const
{ {
for( const XMLNode* node = _lastChild; node; node = node->_prev ) { for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
const XMLElement* element = node->ToElement(); const XMLElement* element = node->ToElementWithName( name );
if ( element ) { if ( element ) {
if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) { return element;
return element;
}
} }
} }
return 0; return 0;
@ -904,9 +933,8 @@ const XMLElement* XMLNode::LastChildElement( const char* name ) const
const XMLElement* XMLNode::NextSiblingElement( const char* name ) const const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
{ {
for( const XMLNode* node = _next; node; node = node->_next ) { for( const XMLNode* node = _next; node; node = node->_next ) {
const XMLElement* element = node->ToElement(); const XMLElement* element = node->ToElementWithName( name );
if ( element if ( element ) {
&& (!name || XMLUtil::StringEqual( name, element->Name() ))) {
return element; return element;
} }
} }
@ -917,9 +945,8 @@ const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
{ {
for( const XMLNode* node = _prev; node; node = node->_prev ) { for( const XMLNode* node = _prev; node; node = node->_prev ) {
const XMLElement* element = node->ToElement(); const XMLElement* element = node->ToElementWithName( name );
if ( element if ( element ) {
&& (!name || XMLUtil::StringEqual( name, element->Name() ))) {
return element; return element;
} }
} }
@ -927,7 +954,7 @@ const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
} }
char* XMLNode::ParseDeep( char* p, StrPair* parentEnd ) char* XMLNode::ParseDeep( char* p, StrPair* parentEnd, int* curLineNumPtr )
{ {
// This is a recursive method, but thinking about it "at the current level" // This is a recursive method, but thinking about it "at the current level"
// it is a pretty simple flat list: // it is a pretty simple flat list:
@ -950,29 +977,42 @@ char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
XMLNode* node = 0; XMLNode* node = 0;
p = _document->Identify( p, &node ); p = _document->Identify( p, &node );
TIXMLASSERT( p );
if ( node == 0 ) { if ( node == 0 ) {
break; break;
} }
int initialLineNum = node->_parseLineNum;
StrPair endTag; StrPair endTag;
p = node->ParseDeep( p, &endTag ); p = node->ParseDeep( p, &endTag, curLineNumPtr );
if ( !p ) { if ( !p ) {
DeleteNode( node ); DeleteNode( node );
if ( !_document->Error() ) { if ( !_document->Error() ) {
_document->SetError( XML_ERROR_PARSING, 0, 0 ); _document->SetError( XML_ERROR_PARSING, 0, 0, initialLineNum);
} }
break; break;
} }
XMLDeclaration* decl = node->ToDeclaration(); XMLDeclaration* decl = node->ToDeclaration();
if ( decl ) { if ( decl ) {
// A declaration can only be the first child of a document. // Declarations are only allowed at document level
// Set error, if document already has children. bool wellLocated = ( ToDocument() != 0 );
if ( !_document->NoChildren() ) { if ( wellLocated ) {
_document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0); // Multiple declarations are allowed but all declarations
DeleteNode( decl ); // must occur before anything else
for ( const XMLNode* existingNode = _document->FirstChild(); existingNode; existingNode = existingNode->NextSibling() ) {
if ( !existingNode->ToDeclaration() ) {
wellLocated = false;
break; break;
}
} }
}
if ( !wellLocated ) {
_document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0, initialLineNum);
DeleteNode( node );
break;
}
} }
XMLElement* ele = node->ToElement(); XMLElement* ele = node->ToElement();
@ -1004,7 +1044,7 @@ char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
} }
} }
if ( mismatch ) { if ( mismatch ) {
_document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0 ); _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0, initialLineNum);
DeleteNode( node ); DeleteNode( node );
break; break;
} }
@ -1035,14 +1075,29 @@ void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
insertThis->_memPool->SetTracked(); insertThis->_memPool->SetTracked();
} }
const XMLElement* XMLNode::ToElementWithName( const char* name ) const
{
const XMLElement* element = this->ToElement();
if ( element == 0 ) {
return 0;
}
if ( name == 0 ) {
return element;
}
if ( XMLUtil::StringEqual( element->Name(), name ) ) {
return element;
}
return 0;
}
// --------- XMLText ---------- // // --------- XMLText ---------- //
char* XMLText::ParseDeep( char* p, StrPair* ) char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
{ {
const char* start = p; const char* start = p;
if ( this->CData() ) { if ( this->CData() ) {
p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION ); p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
if ( !p ) { if ( !p ) {
_document->SetError( XML_ERROR_PARSING_CDATA, start, 0 ); _document->SetError( XML_ERROR_PARSING_CDATA, start, 0, _parseLineNum );
} }
return p; return p;
} }
@ -1052,12 +1107,12 @@ char* XMLText::ParseDeep( char* p, StrPair* )
flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING; flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
} }
p = _value.ParseText( p, "<", flags ); p = _value.ParseText( p, "<", flags, curLineNumPtr );
if ( p && *p ) { if ( p && *p ) {
return p-1; return p-1;
} }
if ( !p ) { if ( !p ) {
_document->SetError( XML_ERROR_PARSING_TEXT, start, 0 ); _document->SetError( XML_ERROR_PARSING_TEXT, start, 0, _parseLineNum );
} }
} }
return 0; return 0;
@ -1101,13 +1156,13 @@ XMLComment::~XMLComment()
} }
char* XMLComment::ParseDeep( char* p, StrPair* ) char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
{ {
// Comment parses as text. // Comment parses as text.
const char* start = p; const char* start = p;
p = _value.ParseText( p, "-->", StrPair::COMMENT ); p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr );
if ( p == 0 ) { if ( p == 0 ) {
_document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 ); _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0, _parseLineNum );
} }
return p; return p;
} }
@ -1151,13 +1206,13 @@ XMLDeclaration::~XMLDeclaration()
} }
char* XMLDeclaration::ParseDeep( char* p, StrPair* ) char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
{ {
// Declaration parses as text. // Declaration parses as text.
const char* start = p; const char* start = p;
p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION ); p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
if ( p == 0 ) { if ( p == 0 ) {
_document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 ); _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0, _parseLineNum );
} }
return p; return p;
} }
@ -1200,14 +1255,14 @@ XMLUnknown::~XMLUnknown()
} }
char* XMLUnknown::ParseDeep( char* p, StrPair* ) char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
{ {
// Unknown parses as text. // Unknown parses as text.
const char* start = p; const char* start = p;
p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION ); p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
if ( !p ) { if ( !p ) {
_document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 ); _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0, _parseLineNum );
} }
return p; return p;
} }
@ -1249,7 +1304,7 @@ const char* XMLAttribute::Value() const
return _value.GetStr(); return _value.GetStr();
} }
char* XMLAttribute::ParseDeep( char* p, bool processEntities ) char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )
{ {
// Parse using the name rules: bug fix, was using ParseText before // Parse using the name rules: bug fix, was using ParseText before
p = _name.ParseName( p ); p = _name.ParseName( p );
@ -1258,13 +1313,13 @@ char* XMLAttribute::ParseDeep( char* p, bool processEntities )
} }
// Skip white space before = // Skip white space before =
p = XMLUtil::SkipWhiteSpace( p ); p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
if ( *p != '=' ) { if ( *p != '=' ) {
return 0; return 0;
} }
++p; // move up to opening quote ++p; // move up to opening quote
p = XMLUtil::SkipWhiteSpace( p ); p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
if ( *p != '\"' && *p != '\'' ) { if ( *p != '\"' && *p != '\'' ) {
return 0; return 0;
} }
@ -1272,7 +1327,7 @@ char* XMLAttribute::ParseDeep( char* p, bool processEntities )
char endTag[2] = { *p, 0 }; char endTag[2] = { *p, 0 };
++p; // move past opening quote ++p; // move past opening quote
p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES ); p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );
return p; return p;
} }
@ -1301,6 +1356,15 @@ XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
} }
XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
{
if (XMLUtil::ToInt64(Value(), value)) {
return XML_SUCCESS;
}
return XML_WRONG_ATTRIBUTE_TYPE;
}
XMLError XMLAttribute::QueryBoolValue( bool* value ) const XMLError XMLAttribute::QueryBoolValue( bool* value ) const
{ {
if ( XMLUtil::ToBool( Value(), value )) { if ( XMLUtil::ToBool( Value(), value )) {
@ -1350,6 +1414,15 @@ void XMLAttribute::SetAttribute( unsigned v )
} }
void XMLAttribute::SetAttribute(int64_t v)
{
char buf[BUF_SIZE];
XMLUtil::ToStr(v, buf, BUF_SIZE);
_value.SetStr(buf);
}
void XMLAttribute::SetAttribute( bool v ) void XMLAttribute::SetAttribute( bool v )
{ {
char buf[BUF_SIZE]; char buf[BUF_SIZE];
@ -1413,6 +1486,47 @@ const char* XMLElement::Attribute( const char* name, const char* value ) const
return 0; return 0;
} }
int XMLElement::IntAttribute(const char* name, int defaultValue) const
{
int i = defaultValue;
QueryIntAttribute(name, &i);
return i;
}
unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const
{
unsigned i = defaultValue;
QueryUnsignedAttribute(name, &i);
return i;
}
int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const
{
int64_t i = defaultValue;
QueryInt64Attribute(name, &i);
return i;
}
bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const
{
bool b = defaultValue;
QueryBoolAttribute(name, &b);
return b;
}
double XMLElement::DoubleAttribute(const char* name, double defaultValue) const
{
double d = defaultValue;
QueryDoubleAttribute(name, &d);
return d;
}
float XMLElement::FloatAttribute(const char* name, float defaultValue) const
{
float f = defaultValue;
QueryFloatAttribute(name, &f);
return f;
}
const char* XMLElement::GetText() const const char* XMLElement::GetText() const
{ {
@ -1450,7 +1564,15 @@ void XMLElement::SetText( unsigned v )
} }
void XMLElement::SetText( bool v ) void XMLElement::SetText(int64_t v)
{
char buf[BUF_SIZE];
XMLUtil::ToStr(v, buf, BUF_SIZE);
SetText(buf);
}
void XMLElement::SetText( bool v )
{ {
char buf[BUF_SIZE]; char buf[BUF_SIZE];
XMLUtil::ToStr( v, buf, BUF_SIZE ); XMLUtil::ToStr( v, buf, BUF_SIZE );
@ -1500,6 +1622,19 @@ XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
} }
XMLError XMLElement::QueryInt64Text(int64_t* ival) const
{
if (FirstChild() && FirstChild()->ToText()) {
const char* t = FirstChild()->Value();
if (XMLUtil::ToInt64(t, ival)) {
return XML_SUCCESS;
}
return XML_CAN_NOT_CONVERT_TEXT;
}
return XML_NO_TEXT_NODE;
}
XMLError XMLElement::QueryBoolText( bool* bval ) const XMLError XMLElement::QueryBoolText( bool* bval ) const
{ {
if ( FirstChild() && FirstChild()->ToText() ) { if ( FirstChild() && FirstChild()->ToText() ) {
@ -1538,6 +1673,47 @@ XMLError XMLElement::QueryFloatText( float* fval ) const
return XML_NO_TEXT_NODE; return XML_NO_TEXT_NODE;
} }
int XMLElement::IntText(int defaultValue) const
{
int i = defaultValue;
QueryIntText(&i);
return i;
}
unsigned XMLElement::UnsignedText(unsigned defaultValue) const
{
unsigned i = defaultValue;
QueryUnsignedText(&i);
return i;
}
int64_t XMLElement::Int64Text(int64_t defaultValue) const
{
int64_t i = defaultValue;
QueryInt64Text(&i);
return i;
}
bool XMLElement::BoolText(bool defaultValue) const
{
bool b = defaultValue;
QueryBoolText(&b);
return b;
}
double XMLElement::DoubleText(double defaultValue) const
{
double d = defaultValue;
QueryDoubleText(&d);
return d;
}
float XMLElement::FloatText(float defaultValue) const
{
float f = defaultValue;
QueryFloatText(&f);
return f;
}
XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name ) XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
@ -1552,17 +1728,17 @@ XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
} }
} }
if ( !attrib ) { if ( !attrib ) {
TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() ); attrib = CreateAttribute();
attrib = new (_document->_attributePool.Alloc() ) XMLAttribute(); TIXMLASSERT( attrib );
attrib->_memPool = &_document->_attributePool;
if ( last ) { if ( last ) {
TIXMLASSERT( last->_next == 0 );
last->_next = attrib; last->_next = attrib;
} }
else { else {
TIXMLASSERT( _rootAttribute == 0 );
_rootAttribute = attrib; _rootAttribute = attrib;
} }
attrib->SetName( name ); attrib->SetName( name );
attrib->_memPool->SetTracked(); // always created and linked.
} }
return attrib; return attrib;
} }
@ -1587,30 +1763,31 @@ void XMLElement::DeleteAttribute( const char* name )
} }
char* XMLElement::ParseAttributes( char* p ) char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )
{ {
const char* start = p; const char* start = p;
XMLAttribute* prevAttribute = 0; XMLAttribute* prevAttribute = 0;
// Read the attributes. // Read the attributes.
while( p ) { while( p ) {
p = XMLUtil::SkipWhiteSpace( p ); p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
if ( !(*p) ) { if ( !(*p) ) {
_document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() ); _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name(), _parseLineNum );
return 0; return 0;
} }
// attribute. // attribute.
if (XMLUtil::IsNameStartChar( *p ) ) { if (XMLUtil::IsNameStartChar( *p ) ) {
TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() ); XMLAttribute* attrib = CreateAttribute();
XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute(); TIXMLASSERT( attrib );
attrib->_memPool = &_document->_attributePool; attrib->_parseLineNum = _document->_parseCurLineNum;
attrib->_memPool->SetTracked();
p = attrib->ParseDeep( p, _document->ProcessEntities() ); int attrLineNum = attrib->_parseLineNum;
p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );
if ( !p || Attribute( attrib->Name() ) ) { if ( !p || Attribute( attrib->Name() ) ) {
DeleteAttribute( attrib ); DeleteAttribute( attrib );
_document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p ); _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p, attrLineNum );
return 0; return 0;
} }
// There is a minor bug here: if the attribute in the source xml // There is a minor bug here: if the attribute in the source xml
@ -1619,9 +1796,11 @@ char* XMLElement::ParseAttributes( char* p )
// avoids re-scanning the attribute list. Preferring performance for // avoids re-scanning the attribute list. Preferring performance for
// now, may reconsider in the future. // now, may reconsider in the future.
if ( prevAttribute ) { if ( prevAttribute ) {
TIXMLASSERT( prevAttribute->_next == 0 );
prevAttribute->_next = attrib; prevAttribute->_next = attrib;
} }
else { else {
TIXMLASSERT( _rootAttribute == 0 );
_rootAttribute = attrib; _rootAttribute = attrib;
} }
prevAttribute = attrib; prevAttribute = attrib;
@ -1637,7 +1816,7 @@ char* XMLElement::ParseAttributes( char* p )
return p+2; // done; sealed element. return p+2; // done; sealed element.
} }
else { else {
_document->SetError( XML_ERROR_PARSING_ELEMENT, start, p ); _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p, _parseLineNum );
return 0; return 0;
} }
} }
@ -1654,14 +1833,23 @@ void XMLElement::DeleteAttribute( XMLAttribute* attribute )
pool->Free( attribute ); pool->Free( attribute );
} }
XMLAttribute* XMLElement::CreateAttribute()
{
TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
attrib->_memPool = &_document->_attributePool;
attrib->_memPool->SetTracked();
return attrib;
}
// //
// <ele></ele> // <ele></ele>
// <ele>foo<b>bar</b></ele> // <ele>foo<b>bar</b></ele>
// //
char* XMLElement::ParseDeep( char* p, StrPair* strPair ) char* XMLElement::ParseDeep( char* p, StrPair* strPair, int* curLineNumPtr )
{ {
// Read the element name. // Read the element name.
p = XMLUtil::SkipWhiteSpace( p ); p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
// The closing element is the </element> form. It is // The closing element is the </element> form. It is
// parsed just like a regular element then deleted from // parsed just like a regular element then deleted from
@ -1676,12 +1864,12 @@ char* XMLElement::ParseDeep( char* p, StrPair* strPair )
return 0; return 0;
} }
p = ParseAttributes( p ); p = ParseAttributes( p, curLineNumPtr );
if ( !p || !*p || _closingType ) { if ( !p || !*p || _closingType ) {
return p; return p;
} }
p = XMLNode::ParseDeep( p, strPair ); p = XMLNode::ParseDeep( p, strPair, curLineNumPtr );
return p; return p;
} }
@ -1773,8 +1961,6 @@ XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
_processEntities( processEntities ), _processEntities( processEntities ),
_errorID(XML_SUCCESS), _errorID(XML_SUCCESS),
_whitespace( whitespace ), _whitespace( whitespace ),
_errorStr1( 0 ),
_errorStr2( 0 ),
_charBuffer( 0 ) _charBuffer( 0 )
{ {
// avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+) // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
@ -1795,9 +1981,7 @@ void XMLDocument::Clear()
#ifdef DEBUG #ifdef DEBUG
const bool hadError = Error(); const bool hadError = Error();
#endif #endif
_errorID = XML_SUCCESS; ClearError();
_errorStr1 = 0;
_errorStr2 = 0;
delete [] _charBuffer; delete [] _charBuffer;
_charBuffer = 0; _charBuffer = 0;
@ -1908,7 +2092,7 @@ XMLError XMLDocument::LoadFile( const char* filename )
Clear(); Clear();
FILE* fp = callfopen( filename, "rb" ); FILE* fp = callfopen( filename, "rb" );
if ( !fp ) { if ( !fp ) {
SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 ); SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0, 0 );
return _errorID; return _errorID;
} }
LoadFile( fp ); LoadFile( fp );
@ -1932,10 +2116,12 @@ struct LongFitsIntoSizeTMinusOne {
}; };
template <> template <>
bool LongFitsIntoSizeTMinusOne<false>::Fits( unsigned long /*value*/ ) struct LongFitsIntoSizeTMinusOne<false> {
{ static bool Fits( unsigned long )
return true; {
} return true;
}
};
XMLError XMLDocument::LoadFile( FILE* fp ) XMLError XMLDocument::LoadFile( FILE* fp )
{ {
@ -1943,7 +2129,7 @@ XMLError XMLDocument::LoadFile( FILE* fp )
fseek( fp, 0, SEEK_SET ); fseek( fp, 0, SEEK_SET );
if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) { if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
return _errorID; return _errorID;
} }
@ -1951,19 +2137,19 @@ XMLError XMLDocument::LoadFile( FILE* fp )
const long filelength = ftell( fp ); const long filelength = ftell( fp );
fseek( fp, 0, SEEK_SET ); fseek( fp, 0, SEEK_SET );
if ( filelength == -1L ) { if ( filelength == -1L ) {
SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
return _errorID; return _errorID;
} }
TIXMLASSERT( filelength >= 0 ); TIXMLASSERT( filelength >= 0 );
if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) { if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
// Cannot handle files which won't fit in buffer together with null terminator // Cannot handle files which won't fit in buffer together with null terminator
SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
return _errorID; return _errorID;
} }
if ( filelength == 0 ) { if ( filelength == 0 ) {
SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
return _errorID; return _errorID;
} }
@ -1972,7 +2158,7 @@ XMLError XMLDocument::LoadFile( FILE* fp )
_charBuffer = new char[size+1]; _charBuffer = new char[size+1];
size_t read = fread( _charBuffer, 1, size, fp ); size_t read = fread( _charBuffer, 1, size, fp );
if ( read != size ) { if ( read != size ) {
SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
return _errorID; return _errorID;
} }
@ -1987,7 +2173,7 @@ XMLError XMLDocument::SaveFile( const char* filename, bool compact )
{ {
FILE* fp = callfopen( filename, "w" ); FILE* fp = callfopen( filename, "w" );
if ( !fp ) { if ( !fp ) {
SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 ); SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0, 0 );
return _errorID; return _errorID;
} }
SaveFile(fp, compact); SaveFile(fp, compact);
@ -2000,7 +2186,7 @@ XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
{ {
// Clear any error from the last save, otherwise it will get reported // Clear any error from the last save, otherwise it will get reported
// for *this* call. // for *this* call.
SetError(XML_SUCCESS, 0, 0); ClearError();
XMLPrinter stream( fp, compact ); XMLPrinter stream( fp, compact );
Print( &stream ); Print( &stream );
return _errorID; return _errorID;
@ -2012,7 +2198,7 @@ XMLError XMLDocument::Parse( const char* p, size_t len )
Clear(); Clear();
if ( len == 0 || !p || !*p ) { if ( len == 0 || !p || !*p ) {
SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
return _errorID; return _errorID;
} }
if ( len == (size_t)(-1) ) { if ( len == (size_t)(-1) ) {
@ -2050,20 +2236,32 @@ void XMLDocument::Print( XMLPrinter* streamer ) const
} }
void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 ) void XMLDocument::SetError( XMLError error, const char* str1, const char* str2, int lineNum )
{ {
TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT ); TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
_errorID = error; _errorID = error;
_errorStr1 = str1;
_errorStr2 = str2; _errorStr1.Reset();
_errorStr2.Reset();
_errorLineNum = lineNum;
if (str1)
_errorStr1.SetStr(str1);
if (str2)
_errorStr2.SetStr(str2);
}
/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)
{
TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
const char* errorName = _errorNames[errorID];
TIXMLASSERT( errorName && errorName[0] );
return errorName;
} }
const char* XMLDocument::ErrorName() const const char* XMLDocument::ErrorName() const
{ {
TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT ); return ErrorIDToName(_errorID);
const char* errorName = _errorNames[_errorID];
TIXMLASSERT( errorName && errorName[0] );
return errorName;
} }
void XMLDocument::PrintError() const void XMLDocument::PrintError() const
@ -2073,18 +2271,18 @@ void XMLDocument::PrintError() const
char buf1[LEN] = { 0 }; char buf1[LEN] = { 0 };
char buf2[LEN] = { 0 }; char buf2[LEN] = { 0 };
if ( _errorStr1 ) { if ( !_errorStr1.Empty() ) {
TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 ); TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1.GetStr() );
} }
if ( _errorStr2 ) { if ( !_errorStr2.Empty() ) {
TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 ); TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2.GetStr() );
} }
// Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
// causes a clang "always true" -Wtautological-constant-out-of-range-compare warning // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX ); TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n", printf( "XMLDocument error id=%d '%s' str1=%s str2=%s line=%d\n",
static_cast<int>( _errorID ), ErrorName(), buf1, buf2 ); static_cast<int>( _errorID ), ErrorName(), buf1, buf2, _errorLineNum );
} }
} }
@ -2092,14 +2290,16 @@ void XMLDocument::Parse()
{ {
TIXMLASSERT( NoChildren() ); // Clear() must have been called previously TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
TIXMLASSERT( _charBuffer ); TIXMLASSERT( _charBuffer );
_parseCurLineNum = 1;
_parseLineNum = 1;
char* p = _charBuffer; char* p = _charBuffer;
p = XMLUtil::SkipWhiteSpace( p ); p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) ); p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
if ( !*p ) { if ( !*p ) {
SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
return; return;
} }
ParseDeep(p, 0 ); ParseDeep(p, 0, &_parseCurLineNum );
} }
XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) : XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
@ -2117,7 +2317,7 @@ XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
} }
for( int i=0; i<NUM_ENTITIES; ++i ) { for( int i=0; i<NUM_ENTITIES; ++i ) {
const char entityValue = entities[i].value; const char entityValue = entities[i].value;
TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE ); TIXMLASSERT( ((unsigned char)entityValue) < ENTITY_RANGE );
_entityFlag[ (unsigned char)entityValue ] = true; _entityFlag[ (unsigned char)entityValue ] = true;
} }
_restrictedEntityFlag[(unsigned char)'&'] = true; _restrictedEntityFlag[(unsigned char)'&'] = true;
@ -2263,6 +2463,14 @@ void XMLPrinter::PushAttribute( const char* name, unsigned v )
} }
void XMLPrinter::PushAttribute(const char* name, int64_t v)
{
char buf[BUF_SIZE];
XMLUtil::ToStr(v, buf, BUF_SIZE);
PushAttribute(name, buf);
}
void XMLPrinter::PushAttribute( const char* name, bool v ) void XMLPrinter::PushAttribute( const char* name, bool v )
{ {
char buf[BUF_SIZE]; char buf[BUF_SIZE];
@ -2328,6 +2536,13 @@ void XMLPrinter::PushText( const char* text, bool cdata )
} }
} }
void XMLPrinter::PushText( int64_t value )
{
char buf[BUF_SIZE];
XMLUtil::ToStr( value, buf, BUF_SIZE );
PushText( buf, false );
}
void XMLPrinter::PushText( int value ) void XMLPrinter::PushText( int value )
{ {
char buf[BUF_SIZE]; char buf[BUF_SIZE];

View File

@ -40,6 +40,7 @@ distribution.
# include <cstdlib> # include <cstdlib>
# include <cstring> # include <cstring>
#endif #endif
#include <stdint.h>
/* /*
TODO: intern strings instead of allocation. TODO: intern strings instead of allocation.
@ -71,6 +72,8 @@ distribution.
# else # else
# define TINYXML2_LIB # define TINYXML2_LIB
# endif # endif
#elif __GNUC__ >= 4
# define TINYXML2_LIB __attribute__((visibility("default")))
#else #else
# define TINYXML2_LIB # define TINYXML2_LIB
#endif #endif
@ -95,9 +98,9 @@ distribution.
/* Versioning, past 1.0.14: /* Versioning, past 1.0.14:
http://semver.org/ http://semver.org/
*/ */
static const int TIXML2_MAJOR_VERSION = 3; static const int TIXML2_MAJOR_VERSION = 4;
static const int TIXML2_MINOR_VERSION = 0; static const int TIXML2_MINOR_VERSION = 0;
static const int TIXML2_PATCH_VERSION = 0; static const int TIXML2_PATCH_VERSION = 1;
namespace tinyxml2 namespace tinyxml2
{ {
@ -124,18 +127,20 @@ public:
NEEDS_NEWLINE_NORMALIZATION = 0x02, NEEDS_NEWLINE_NORMALIZATION = 0x02,
NEEDS_WHITESPACE_COLLAPSING = 0x04, NEEDS_WHITESPACE_COLLAPSING = 0x04,
TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION, TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
TEXT_ELEMENT_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION, TEXT_ELEMENT_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,
ATTRIBUTE_NAME = 0, ATTRIBUTE_NAME = 0,
ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION, ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
ATTRIBUTE_VALUE_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION, ATTRIBUTE_VALUE_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,
COMMENT = NEEDS_NEWLINE_NORMALIZATION COMMENT = NEEDS_NEWLINE_NORMALIZATION
}; };
StrPair() : _flags( 0 ), _start( 0 ), _end( 0 ) {} StrPair() : _flags( 0 ), _start( 0 ), _end( 0 ) {}
~StrPair(); ~StrPair();
void Set( char* start, char* end, int flags ) { void Set( char* start, char* end, int flags ) {
TIXMLASSERT( start );
TIXMLASSERT( end );
Reset(); Reset();
_start = start; _start = start;
_end = end; _end = end;
@ -155,13 +160,13 @@ public:
void SetStr( const char* str, int flags=0 ); void SetStr( const char* str, int flags=0 );
char* ParseText( char* in, const char* endTag, int strFlags ); char* ParseText( char* in, const char* endTag, int strFlags, int* curLineNumPtr );
char* ParseName( char* in ); char* ParseName( char* in );
void TransferTo( StrPair* other ); void TransferTo( StrPair* other );
void Reset();
private: private:
void Reset();
void CollapseWhitespace(); void CollapseWhitespace();
enum { enum {
@ -206,7 +211,8 @@ public:
void Push( T t ) { void Push( T t ) {
TIXMLASSERT( _size < INT_MAX ); TIXMLASSERT( _size < INT_MAX );
EnsureCapacity( _size+1 ); EnsureCapacity( _size+1 );
_mem[_size++] = t; _mem[_size] = t;
++_size;
} }
T* PushArr( int count ) { T* PushArr( int count ) {
@ -220,7 +226,8 @@ public:
T Pop() { T Pop() {
TIXMLASSERT( _size > 0 ); TIXMLASSERT( _size > 0 );
return _mem[--_size]; --_size;
return _mem[_size];
} }
void PopArr( int count ) { void PopArr( int count ) {
@ -314,7 +321,7 @@ public:
/* /*
Template child class to create pools of the correct type. Template child class to create pools of the correct type.
*/ */
template< int SIZE > template< int ITEM_SIZE >
class MemPoolT : public MemPool class MemPoolT : public MemPool
{ {
public: public:
@ -337,7 +344,7 @@ public:
} }
virtual int ItemSize() const { virtual int ItemSize() const {
return SIZE; return ITEM_SIZE;
} }
int CurrentAllocs() const { int CurrentAllocs() const {
return _currentAllocs; return _currentAllocs;
@ -349,21 +356,23 @@ public:
Block* block = new Block(); Block* block = new Block();
_blockPtrs.Push( block ); _blockPtrs.Push( block );
for( int i=0; i<COUNT-1; ++i ) { Item* blockItems = block->items;
block->chunk[i].next = &block->chunk[i+1]; for( int i = 0; i < ITEMS_PER_BLOCK - 1; ++i ) {
blockItems[i].next = &(blockItems[i + 1]);
} }
block->chunk[COUNT-1].next = 0; blockItems[ITEMS_PER_BLOCK - 1].next = 0;
_root = block->chunk; _root = blockItems;
} }
void* result = _root; Item* const result = _root;
TIXMLASSERT( result != 0 );
_root = _root->next; _root = _root->next;
++_currentAllocs; ++_currentAllocs;
if ( _currentAllocs > _maxAllocs ) { if ( _currentAllocs > _maxAllocs ) {
_maxAllocs = _currentAllocs; _maxAllocs = _currentAllocs;
} }
_nAllocs++; ++_nAllocs;
_nUntracked++; ++_nUntracked;
return result; return result;
} }
@ -372,20 +381,21 @@ public:
return; return;
} }
--_currentAllocs; --_currentAllocs;
Chunk* chunk = static_cast<Chunk*>( mem ); Item* item = static_cast<Item*>( mem );
#ifdef DEBUG #ifdef DEBUG
memset( chunk, 0xfe, sizeof(Chunk) ); memset( item, 0xfe, sizeof( *item ) );
#endif #endif
chunk->next = _root; item->next = _root;
_root = chunk; _root = item;
} }
void Trace( const char* name ) { void Trace( const char* name ) {
printf( "Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\n", printf( "Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\n",
name, _maxAllocs, _maxAllocs*SIZE/1024, _currentAllocs, SIZE, _nAllocs, _blockPtrs.Size() ); name, _maxAllocs, _maxAllocs * ITEM_SIZE / 1024, _currentAllocs,
ITEM_SIZE, _nAllocs, _blockPtrs.Size() );
} }
void SetTracked() { void SetTracked() {
_nUntracked--; --_nUntracked;
} }
int Untracked() const { int Untracked() const {
@ -401,21 +411,23 @@ public:
// 16k: 5200 // 16k: 5200
// 32k: 4300 // 32k: 4300
// 64k: 4000 21000 // 64k: 4000 21000
enum { COUNT = (4*1024)/SIZE }; // Some compilers do not accept to use COUNT in private part if COUNT is private // Declared public because some compilers do not accept to use ITEMS_PER_BLOCK
// in private part if ITEMS_PER_BLOCK is private
enum { ITEMS_PER_BLOCK = (4 * 1024) / ITEM_SIZE };
private: private:
MemPoolT( const MemPoolT& ); // not supported MemPoolT( const MemPoolT& ); // not supported
void operator=( const MemPoolT& ); // not supported void operator=( const MemPoolT& ); // not supported
union Chunk { union Item {
Chunk* next; Item* next;
char mem[SIZE]; char itemData[ITEM_SIZE];
}; };
struct Block { struct Block {
Chunk chunk[COUNT]; Item items[ITEMS_PER_BLOCK];
}; };
DynArray< Block*, 10 > _blockPtrs; DynArray< Block*, 10 > _blockPtrs;
Chunk* _root; Item* _root;
int _currentAllocs; int _currentAllocs;
int _nAllocs; int _nAllocs;
@ -518,16 +530,20 @@ enum XMLError {
class XMLUtil class XMLUtil
{ {
public: public:
static const char* SkipWhiteSpace( const char* p ) { static const char* SkipWhiteSpace( const char* p, int* curLineNumPtr ) {
TIXMLASSERT( p ); TIXMLASSERT( p );
while( IsWhiteSpace(*p) ) { while( IsWhiteSpace(*p) ) {
if (curLineNumPtr && *p == '\n') {
++(*curLineNumPtr);
}
++p; ++p;
} }
TIXMLASSERT( p ); TIXMLASSERT( p );
return p; return p;
} }
static char* SkipWhiteSpace( char* p ) { static char* SkipWhiteSpace( char* p, int* curLineNumPtr ) {
return const_cast<char*>( SkipWhiteSpace( const_cast<const char*>(p) ) ); return const_cast<char*>( SkipWhiteSpace( const_cast<const char*>(p), curLineNumPtr ) );
} }
// Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't // Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't
@ -558,6 +574,9 @@ public:
if ( p == q ) { if ( p == q ) {
return true; return true;
} }
TIXMLASSERT( p );
TIXMLASSERT( q );
TIXMLASSERT( nChar >= 0 );
return strncmp( p, q, nChar ) == 0; return strncmp( p, q, nChar ) == 0;
} }
@ -577,6 +596,7 @@ public:
static void ToStr( bool v, char* buffer, int bufferSize ); static void ToStr( bool v, char* buffer, int bufferSize );
static void ToStr( float v, char* buffer, int bufferSize ); static void ToStr( float v, char* buffer, int bufferSize );
static void ToStr( double v, char* buffer, int bufferSize ); static void ToStr( double v, char* buffer, int bufferSize );
static void ToStr(int64_t v, char* buffer, int bufferSize);
// converts strings to primitive types // converts strings to primitive types
static bool ToInt( const char* str, int* value ); static bool ToInt( const char* str, int* value );
@ -584,6 +604,7 @@ public:
static bool ToBool( const char* str, bool* value ); static bool ToBool( const char* str, bool* value );
static bool ToFloat( const char* str, float* value ); static bool ToFloat( const char* str, float* value );
static bool ToDouble( const char* str, double* value ); static bool ToDouble( const char* str, double* value );
static bool ToInt64(const char* str, int64_t* value);
}; };
@ -689,6 +710,9 @@ public:
*/ */
void SetValue( const char* val, bool staticMem=false ); void SetValue( const char* val, bool staticMem=false );
/// Gets the line number the node is in, if the document was parsed from a file.
int GetLineNum() const { return _parseLineNum; }
/// Get the parent of this node on the DOM. /// Get the parent of this node on the DOM.
const XMLNode* Parent() const { const XMLNode* Parent() const {
return _parent; return _parent;
@ -854,15 +878,30 @@ public:
*/ */
virtual bool Accept( XMLVisitor* visitor ) const = 0; virtual bool Accept( XMLVisitor* visitor ) const = 0;
/**
Set user data into the XMLNode. TinyXML-2 in
no way processes or interprets user data.
It is initially 0.
*/
void SetUserData(void* userData) { _userData = userData; }
/**
Get user data set into the XMLNode. TinyXML-2 in
no way processes or interprets user data.
It is initially 0.
*/
void* GetUserData() const { return _userData; }
protected: protected:
XMLNode( XMLDocument* ); XMLNode( XMLDocument* );
virtual ~XMLNode(); virtual ~XMLNode();
virtual char* ParseDeep( char*, StrPair* ); virtual char* ParseDeep( char*, StrPair*, int* );
XMLDocument* _document; XMLDocument* _document;
XMLNode* _parent; XMLNode* _parent;
mutable StrPair _value; mutable StrPair _value;
int _parseLineNum;
XMLNode* _firstChild; XMLNode* _firstChild;
XMLNode* _lastChild; XMLNode* _lastChild;
@ -870,11 +909,14 @@ protected:
XMLNode* _prev; XMLNode* _prev;
XMLNode* _next; XMLNode* _next;
void* _userData;
private: private:
MemPool* _memPool; MemPool* _memPool;
void Unlink( XMLNode* child ); void Unlink( XMLNode* child );
static void DeleteNode( XMLNode* node ); static void DeleteNode( XMLNode* node );
void InsertChildPreamble( XMLNode* insertThis ) const; void InsertChildPreamble( XMLNode* insertThis ) const;
const XMLElement* ToElementWithName( const char* name ) const;
XMLNode( const XMLNode& ); // not supported XMLNode( const XMLNode& ); // not supported
XMLNode& operator=( const XMLNode& ); // not supported XMLNode& operator=( const XMLNode& ); // not supported
@ -922,7 +964,7 @@ protected:
XMLText( XMLDocument* doc ) : XMLNode( doc ), _isCData( false ) {} XMLText( XMLDocument* doc ) : XMLNode( doc ), _isCData( false ) {}
virtual ~XMLText() {} virtual ~XMLText() {}
char* ParseDeep( char*, StrPair* endTag ); char* ParseDeep( char*, StrPair* endTag, int* curLineNumPtr );
private: private:
bool _isCData; bool _isCData;
@ -953,7 +995,7 @@ protected:
XMLComment( XMLDocument* doc ); XMLComment( XMLDocument* doc );
virtual ~XMLComment(); virtual ~XMLComment();
char* ParseDeep( char*, StrPair* endTag ); char* ParseDeep( char*, StrPair* endTag, int* curLineNumPtr);
private: private:
XMLComment( const XMLComment& ); // not supported XMLComment( const XMLComment& ); // not supported
@ -992,7 +1034,7 @@ protected:
XMLDeclaration( XMLDocument* doc ); XMLDeclaration( XMLDocument* doc );
virtual ~XMLDeclaration(); virtual ~XMLDeclaration();
char* ParseDeep( char*, StrPair* endTag ); char* ParseDeep( char*, StrPair* endTag, int* curLineNumPtr );
private: private:
XMLDeclaration( const XMLDeclaration& ); // not supported XMLDeclaration( const XMLDeclaration& ); // not supported
@ -1027,7 +1069,7 @@ protected:
XMLUnknown( XMLDocument* doc ); XMLUnknown( XMLDocument* doc );
virtual ~XMLUnknown(); virtual ~XMLUnknown();
char* ParseDeep( char*, StrPair* endTag ); char* ParseDeep( char*, StrPair* endTag, int* curLineNumPtr );
private: private:
XMLUnknown( const XMLUnknown& ); // not supported XMLUnknown( const XMLUnknown& ); // not supported
@ -1052,6 +1094,9 @@ public:
/// The value of the attribute. /// The value of the attribute.
const char* Value() const; const char* Value() const;
/// Gets the line number the attribute is in, if the document was parsed from a file.
int GetLineNum() const { return _parseLineNum; }
/// The next attribute in the list. /// The next attribute in the list.
const XMLAttribute* Next() const { const XMLAttribute* Next() const {
return _next; return _next;
@ -1061,11 +1106,18 @@ public:
If the value isn't an integer, 0 will be returned. There is no error checking; If the value isn't an integer, 0 will be returned. There is no error checking;
use QueryIntValue() if you need error checking. use QueryIntValue() if you need error checking.
*/ */
int IntValue() const { int IntValue() const {
int i=0; int i = 0;
QueryIntValue( &i ); QueryIntValue(&i);
return i; return i;
} }
int64_t Int64Value() const {
int64_t i = 0;
QueryInt64Value(&i);
return i;
}
/// Query as an unsigned integer. See IntValue() /// Query as an unsigned integer. See IntValue()
unsigned UnsignedValue() const { unsigned UnsignedValue() const {
unsigned i=0; unsigned i=0;
@ -1092,13 +1144,15 @@ public:
} }
/** QueryIntValue interprets the attribute as an integer, and returns the value /** QueryIntValue interprets the attribute as an integer, and returns the value
in the provided parameter. The function will return XML_NO_ERROR on success, in the provided parameter. The function will return XML_SUCCESS on success,
and XML_WRONG_ATTRIBUTE_TYPE if the conversion is not successful. and XML_WRONG_ATTRIBUTE_TYPE if the conversion is not successful.
*/ */
XMLError QueryIntValue( int* value ) const; XMLError QueryIntValue( int* value ) const;
/// See QueryIntValue /// See QueryIntValue
XMLError QueryUnsignedValue( unsigned int* value ) const; XMLError QueryUnsignedValue( unsigned int* value ) const;
/// See QueryIntValue /// See QueryIntValue
XMLError QueryInt64Value(int64_t* value) const;
/// See QueryIntValue
XMLError QueryBoolValue( bool* value ) const; XMLError QueryBoolValue( bool* value ) const;
/// See QueryIntValue /// See QueryIntValue
XMLError QueryDoubleValue( double* value ) const; XMLError QueryDoubleValue( double* value ) const;
@ -1111,7 +1165,9 @@ public:
void SetAttribute( int value ); void SetAttribute( int value );
/// Set the attribute to value. /// Set the attribute to value.
void SetAttribute( unsigned value ); void SetAttribute( unsigned value );
/// Set the attribute to value. /// Set the attribute to value.
void SetAttribute(int64_t value);
/// Set the attribute to value.
void SetAttribute( bool value ); void SetAttribute( bool value );
/// Set the attribute to value. /// Set the attribute to value.
void SetAttribute( double value ); void SetAttribute( double value );
@ -1128,10 +1184,11 @@ private:
void operator=( const XMLAttribute& ); // not supported void operator=( const XMLAttribute& ); // not supported
void SetName( const char* name ); void SetName( const char* name );
char* ParseDeep( char* p, bool processEntities ); char* ParseDeep( char* p, bool processEntities, int* curLineNumPtr );
mutable StrPair _name; mutable StrPair _name;
mutable StrPair _value; mutable StrPair _value;
int _parseLineNum;
XMLAttribute* _next; XMLAttribute* _next;
MemPool* _memPool; MemPool* _memPool;
}; };
@ -1188,42 +1245,25 @@ public:
const char* Attribute( const char* name, const char* value=0 ) const; const char* Attribute( const char* name, const char* value=0 ) const;
/** Given an attribute name, IntAttribute() returns the value /** Given an attribute name, IntAttribute() returns the value
of the attribute interpreted as an integer. 0 will be of the attribute interpreted as an integer. The default
returned if there is an error. For a method with error value will be returned if the attribute isn't present,
checking, see QueryIntAttribute() or if there is an error. (For a method with error
checking, see QueryIntAttribute()).
*/ */
int IntAttribute( const char* name ) const { int IntAttribute(const char* name, int defaultValue = 0) const;
int i=0;
QueryIntAttribute( name, &i );
return i;
}
/// See IntAttribute() /// See IntAttribute()
unsigned UnsignedAttribute( const char* name ) const { unsigned UnsignedAttribute(const char* name, unsigned defaultValue = 0) const;
unsigned i=0; /// See IntAttribute()
QueryUnsignedAttribute( name, &i ); int64_t Int64Attribute(const char* name, int64_t defaultValue = 0) const;
return i; /// See IntAttribute()
} bool BoolAttribute(const char* name, bool defaultValue = false) const;
/// See IntAttribute() /// See IntAttribute()
bool BoolAttribute( const char* name ) const { double DoubleAttribute(const char* name, double defaultValue = 0) const;
bool b=false;
QueryBoolAttribute( name, &b );
return b;
}
/// See IntAttribute() /// See IntAttribute()
double DoubleAttribute( const char* name ) const { float FloatAttribute(const char* name, float defaultValue = 0) const;
double d=0;
QueryDoubleAttribute( name, &d );
return d;
}
/// See IntAttribute()
float FloatAttribute( const char* name ) const {
float f=0;
QueryFloatAttribute( name, &f );
return f;
}
/** Given an attribute name, QueryIntAttribute() returns /** Given an attribute name, QueryIntAttribute() returns
XML_NO_ERROR, XML_WRONG_ATTRIBUTE_TYPE if the conversion XML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion
can't be performed, or XML_NO_ATTRIBUTE if the attribute can't be performed, or XML_NO_ATTRIBUTE if the attribute
doesn't exist. If successful, the result of the conversion doesn't exist. If successful, the result of the conversion
will be written to 'value'. If not successful, nothing will will be written to 'value'. If not successful, nothing will
@ -1242,7 +1282,8 @@ public:
} }
return a->QueryIntValue( value ); return a->QueryIntValue( value );
} }
/// See QueryIntAttribute()
/// See QueryIntAttribute()
XMLError QueryUnsignedAttribute( const char* name, unsigned int* value ) const { XMLError QueryUnsignedAttribute( const char* name, unsigned int* value ) const {
const XMLAttribute* a = FindAttribute( name ); const XMLAttribute* a = FindAttribute( name );
if ( !a ) { if ( !a ) {
@ -1250,7 +1291,17 @@ public:
} }
return a->QueryUnsignedValue( value ); return a->QueryUnsignedValue( value );
} }
/// See QueryIntAttribute()
/// See QueryIntAttribute()
XMLError QueryInt64Attribute(const char* name, int64_t* value) const {
const XMLAttribute* a = FindAttribute(name);
if (!a) {
return XML_NO_ATTRIBUTE;
}
return a->QueryInt64Value(value);
}
/// See QueryIntAttribute()
XMLError QueryBoolAttribute( const char* name, bool* value ) const { XMLError QueryBoolAttribute( const char* name, bool* value ) const {
const XMLAttribute* a = FindAttribute( name ); const XMLAttribute* a = FindAttribute( name );
if ( !a ) { if ( !a ) {
@ -1277,7 +1328,7 @@ public:
/** Given an attribute name, QueryAttribute() returns /** Given an attribute name, QueryAttribute() returns
XML_NO_ERROR, XML_WRONG_ATTRIBUTE_TYPE if the conversion XML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion
can't be performed, or XML_NO_ATTRIBUTE if the attribute can't be performed, or XML_NO_ATTRIBUTE if the attribute
doesn't exist. It is overloaded for the primitive types, doesn't exist. It is overloaded for the primitive types,
and is a generally more convenient replacement of and is a generally more convenient replacement of
@ -1301,6 +1352,10 @@ public:
return QueryUnsignedAttribute( name, value ); return QueryUnsignedAttribute( name, value );
} }
int QueryAttribute(const char* name, int64_t* value) const {
return QueryInt64Attribute(name, value);
}
int QueryAttribute( const char* name, bool* value ) const { int QueryAttribute( const char* name, bool* value ) const {
return QueryBoolAttribute( name, value ); return QueryBoolAttribute( name, value );
} }
@ -1328,7 +1383,14 @@ public:
XMLAttribute* a = FindOrCreateAttribute( name ); XMLAttribute* a = FindOrCreateAttribute( name );
a->SetAttribute( value ); a->SetAttribute( value );
} }
/// Sets the named attribute to value.
/// Sets the named attribute to value.
void SetAttribute(const char* name, int64_t value) {
XMLAttribute* a = FindOrCreateAttribute(name);
a->SetAttribute(value);
}
/// Sets the named attribute to value.
void SetAttribute( const char* name, bool value ) { void SetAttribute( const char* name, bool value ) {
XMLAttribute* a = FindOrCreateAttribute( name ); XMLAttribute* a = FindOrCreateAttribute( name );
a->SetAttribute( value ); a->SetAttribute( value );
@ -1425,7 +1487,9 @@ public:
void SetText( int value ); void SetText( int value );
/// Convenience method for setting text inside an element. See SetText() for important limitations. /// Convenience method for setting text inside an element. See SetText() for important limitations.
void SetText( unsigned value ); void SetText( unsigned value );
/// Convenience method for setting text inside an element. See SetText() for important limitations. /// Convenience method for setting text inside an element. See SetText() for important limitations.
void SetText(int64_t value);
/// Convenience method for setting text inside an element. See SetText() for important limitations.
void SetText( bool value ); void SetText( bool value );
/// Convenience method for setting text inside an element. See SetText() for important limitations. /// Convenience method for setting text inside an element. See SetText() for important limitations.
void SetText( double value ); void SetText( double value );
@ -1461,13 +1525,28 @@ public:
XMLError QueryIntText( int* ival ) const; XMLError QueryIntText( int* ival ) const;
/// See QueryIntText() /// See QueryIntText()
XMLError QueryUnsignedText( unsigned* uval ) const; XMLError QueryUnsignedText( unsigned* uval ) const;
/// See QueryIntText() /// See QueryIntText()
XMLError QueryInt64Text(int64_t* uval) const;
/// See QueryIntText()
XMLError QueryBoolText( bool* bval ) const; XMLError QueryBoolText( bool* bval ) const;
/// See QueryIntText() /// See QueryIntText()
XMLError QueryDoubleText( double* dval ) const; XMLError QueryDoubleText( double* dval ) const;
/// See QueryIntText() /// See QueryIntText()
XMLError QueryFloatText( float* fval ) const; XMLError QueryFloatText( float* fval ) const;
int IntText(int defaultValue = 0) const;
/// See QueryIntText()
unsigned UnsignedText(unsigned defaultValue = 0) const;
/// See QueryIntText()
int64_t Int64Text(int64_t defaultValue = 0) const;
/// See QueryIntText()
bool BoolText(bool defaultValue = false) const;
/// See QueryIntText()
double DoubleText(double defaultValue = 0) const;
/// See QueryIntText()
float FloatText(float defaultValue = 0) const;
// internal: // internal:
enum { enum {
OPEN, // <foo> OPEN, // <foo>
@ -1481,7 +1560,7 @@ public:
virtual bool ShallowEqual( const XMLNode* compare ) const; virtual bool ShallowEqual( const XMLNode* compare ) const;
protected: protected:
char* ParseDeep( char* p, StrPair* endTag ); char* ParseDeep( char* p, StrPair* endTag, int* curLineNumPtr );
private: private:
XMLElement( XMLDocument* doc ); XMLElement( XMLDocument* doc );
@ -1494,8 +1573,9 @@ private:
} }
XMLAttribute* FindOrCreateAttribute( const char* name ); XMLAttribute* FindOrCreateAttribute( const char* name );
//void LinkAttribute( XMLAttribute* attrib ); //void LinkAttribute( XMLAttribute* attrib );
char* ParseAttributes( char* p ); char* ParseAttributes( char* p, int* curLineNumPtr );
static void DeleteAttribute( XMLAttribute* attribute ); static void DeleteAttribute( XMLAttribute* attribute );
XMLAttribute* CreateAttribute();
enum { BUF_SIZE = 200 }; enum { BUF_SIZE = 200 };
int _closingType; int _closingType;
@ -1536,7 +1616,7 @@ public:
/** /**
Parse an XML file from a character string. Parse an XML file from a character string.
Returns XML_NO_ERROR (0) on success, or Returns XML_SUCCESS (0) on success, or
an errorID. an errorID.
You may optionally pass in the 'nBytes', which is You may optionally pass in the 'nBytes', which is
@ -1548,7 +1628,7 @@ public:
/** /**
Load an XML file from disk. Load an XML file from disk.
Returns XML_NO_ERROR (0) on success, or Returns XML_SUCCESS (0) on success, or
an errorID. an errorID.
*/ */
XMLError LoadFile( const char* filename ); XMLError LoadFile( const char* filename );
@ -1561,14 +1641,14 @@ public:
not text in order for TinyXML-2 to correctly not text in order for TinyXML-2 to correctly
do newline normalization. do newline normalization.
Returns XML_NO_ERROR (0) on success, or Returns XML_SUCCESS (0) on success, or
an errorID. an errorID.
*/ */
XMLError LoadFile( FILE* ); XMLError LoadFile( FILE* );
/** /**
Save the XML file to disk. Save the XML file to disk.
Returns XML_NO_ERROR (0) on success, or Returns XML_SUCCESS (0) on success, or
an errorID. an errorID.
*/ */
XMLError SaveFile( const char* filename, bool compact = false ); XMLError SaveFile( const char* filename, bool compact = false );
@ -1577,7 +1657,7 @@ public:
Save the XML file to disk. You are responsible Save the XML file to disk. You are responsible
for providing and closing the FILE*. for providing and closing the FILE*.
Returns XML_NO_ERROR (0) on success, or Returns XML_SUCCESS (0) on success, or
an errorID. an errorID.
*/ */
XMLError SaveFile( FILE* fp, bool compact = false ); XMLError SaveFile( FILE* fp, bool compact = false );
@ -1671,7 +1751,11 @@ public:
*/ */
void DeleteNode( XMLNode* node ); void DeleteNode( XMLNode* node );
void SetError( XMLError error, const char* str1, const char* str2 ); void SetError( XMLError error, const char* str1, const char* str2, int lineNum );
void ClearError() {
SetError(XML_SUCCESS, 0, 0, 0);
}
/// Return true if there was an error parsing the document. /// Return true if there was an error parsing the document.
bool Error() const { bool Error() const {
@ -1682,14 +1766,20 @@ public:
return _errorID; return _errorID;
} }
const char* ErrorName() const; const char* ErrorName() const;
static const char* ErrorIDToName(XMLError errorID);
/// Return a possibly helpful diagnostic location or string. /// Return a possibly helpful diagnostic location or string.
const char* GetErrorStr1() const { const char* GetErrorStr1() const {
return _errorStr1; return _errorStr1.GetStr();
} }
/// Return a possibly helpful secondary diagnostic location or string. /// Return a possibly helpful secondary diagnostic location or string.
const char* GetErrorStr2() const { const char* GetErrorStr2() const {
return _errorStr2; return _errorStr2.GetStr();
}
/// Return the line where the error occured, or zero if unknown.
int GetErrorLineNum() const
{
return _errorLineNum;
} }
/// If there is an error, print it to stdout. /// If there is an error, print it to stdout.
void PrintError() const; void PrintError() const;
@ -1711,13 +1801,15 @@ private:
XMLDocument( const XMLDocument& ); // not supported XMLDocument( const XMLDocument& ); // not supported
void operator=( const XMLDocument& ); // not supported void operator=( const XMLDocument& ); // not supported
bool _writeBOM; bool _writeBOM;
bool _processEntities; bool _processEntities;
XMLError _errorID; XMLError _errorID;
Whitespace _whitespace; Whitespace _whitespace;
const char* _errorStr1; mutable StrPair _errorStr1;
const char* _errorStr2; mutable StrPair _errorStr2;
char* _charBuffer; int _errorLineNum;
char* _charBuffer;
int _parseCurLineNum;
MemPoolT< sizeof(XMLElement) > _elementPool; MemPoolT< sizeof(XMLElement) > _elementPool;
MemPoolT< sizeof(XMLAttribute) > _attributePool; MemPoolT< sizeof(XMLAttribute) > _attributePool;
@ -1845,19 +1937,19 @@ public:
} }
/// Safe cast to XMLElement. This can return null. /// Safe cast to XMLElement. This can return null.
XMLElement* ToElement() { XMLElement* ToElement() {
return ( ( _node == 0 ) ? 0 : _node->ToElement() ); return ( _node ? _node->ToElement() : 0 );
} }
/// Safe cast to XMLText. This can return null. /// Safe cast to XMLText. This can return null.
XMLText* ToText() { XMLText* ToText() {
return ( ( _node == 0 ) ? 0 : _node->ToText() ); return ( _node ? _node->ToText() : 0 );
} }
/// Safe cast to XMLUnknown. This can return null. /// Safe cast to XMLUnknown. This can return null.
XMLUnknown* ToUnknown() { XMLUnknown* ToUnknown() {
return ( ( _node == 0 ) ? 0 : _node->ToUnknown() ); return ( _node ? _node->ToUnknown() : 0 );
} }
/// Safe cast to XMLDeclaration. This can return null. /// Safe cast to XMLDeclaration. This can return null.
XMLDeclaration* ToDeclaration() { XMLDeclaration* ToDeclaration() {
return ( ( _node == 0 ) ? 0 : _node->ToDeclaration() ); return ( _node ? _node->ToDeclaration() : 0 );
} }
private: private:
@ -1917,16 +2009,16 @@ public:
return _node; return _node;
} }
const XMLElement* ToElement() const { const XMLElement* ToElement() const {
return ( ( _node == 0 ) ? 0 : _node->ToElement() ); return ( _node ? _node->ToElement() : 0 );
} }
const XMLText* ToText() const { const XMLText* ToText() const {
return ( ( _node == 0 ) ? 0 : _node->ToText() ); return ( _node ? _node->ToText() : 0 );
} }
const XMLUnknown* ToUnknown() const { const XMLUnknown* ToUnknown() const {
return ( ( _node == 0 ) ? 0 : _node->ToUnknown() ); return ( _node ? _node->ToUnknown() : 0 );
} }
const XMLDeclaration* ToDeclaration() const { const XMLDeclaration* ToDeclaration() const {
return ( ( _node == 0 ) ? 0 : _node->ToDeclaration() ); return ( _node ? _node->ToDeclaration() : 0 );
} }
private: private:
@ -1998,7 +2090,8 @@ public:
void PushAttribute( const char* name, const char* value ); void PushAttribute( const char* name, const char* value );
void PushAttribute( const char* name, int value ); void PushAttribute( const char* name, int value );
void PushAttribute( const char* name, unsigned value ); void PushAttribute( const char* name, unsigned value );
void PushAttribute( const char* name, bool value ); void PushAttribute(const char* name, int64_t value);
void PushAttribute( const char* name, bool value );
void PushAttribute( const char* name, double value ); void PushAttribute( const char* name, double value );
/// If streaming, close the Element. /// If streaming, close the Element.
virtual void CloseElement( bool compactMode=false ); virtual void CloseElement( bool compactMode=false );
@ -2009,7 +2102,9 @@ public:
void PushText( int value ); void PushText( int value );
/// Add a text node from an unsigned. /// Add a text node from an unsigned.
void PushText( unsigned value ); void PushText( unsigned value );
/// Add a text node from a bool. /// Add a text node from an unsigned.
void PushText(int64_t value);
/// Add a text node from a bool.
void PushText( bool value ); void PushText( bool value );
/// Add a text node from a float. /// Add a text node from a float.
void PushText( float value ); void PushText( float value );