From b86a39d38ad76630f9c9facf1d100c8d473075a6 Mon Sep 17 00:00:00 2001 From: PKEuS Date: Thu, 29 Dec 2016 11:28:25 +0100 Subject: [PATCH] Updated TinyXML and simplecpp --- externals/simplecpp/simplecpp.cpp | 8 +- externals/tinyxml/tinyxml2.cpp | 435 ++++++++++++++++++++++-------- externals/tinyxml/tinyxml2.h | 319 ++++++++++++++-------- 3 files changed, 536 insertions(+), 226 deletions(-) diff --git a/externals/simplecpp/simplecpp.cpp b/externals/simplecpp/simplecpp.cpp index c5d6d64bd..a906d2d1c 100644 --- a/externals/simplecpp/simplecpp.cpp +++ b/externals/simplecpp/simplecpp.cpp @@ -73,7 +73,7 @@ namespace { long long stringToLL(const std::string &s) { 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); if (hex) istr >> std::hex; @@ -84,7 +84,7 @@ namespace { unsigned long long stringToULL(const std::string &s) { 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); if (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') { std::string delim; ch = readChar(istr,bom); - while (istr.good() && ch != '(' && ch != '\"' && ch != '\n') { + while (istr.good() && ch != '(' && ch != '\n') { delim += ch; ch = readChar(istr,bom); } - if (!istr.good() || ch == '\"' || ch == '\n') + if (!istr.good() || ch == '\n') // TODO report return; currentToken = '\"'; diff --git a/externals/tinyxml/tinyxml2.cpp b/externals/tinyxml/tinyxml2.cpp index bfd8d1f9e..018f9a9ea 100644 --- a/externals/tinyxml/tinyxml2.cpp +++ b/externals/tinyxml/tinyxml2.cpp @@ -149,6 +149,7 @@ void StrPair::TransferTo( StrPair* other ) // This in effect implements the assignment operator by "moving" // ownership (as in auto_ptr). + TIXMLASSERT( other != 0 ); TIXMLASSERT( other->_flags == 0 ); TIXMLASSERT( other->_start == 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(curLineNumPtr); char* start = p; 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 ) { Set( start, p, strFlags ); return p + length; + } else if (*p == '\n') { + ++(*curLineNumPtr); } ++p; + TIXMLASSERT( p ); } return 0; } @@ -233,15 +239,15 @@ void StrPair::CollapseWhitespace() // Adjusting _start would cause undefined behavior on delete[] TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 ); // Trim leading space. - _start = XMLUtil::SkipWhiteSpace( _start ); + _start = XMLUtil::SkipWhiteSpace( _start, 0 ); if ( *_start ) { - char* p = _start; // the read pointer + const char* p = _start; // the read pointer char* q = _start; // the write pointer while( *p ) { if ( XMLUtil::IsWhiteSpace( *p )) { - p = XMLUtil::SkipWhiteSpace( p ); + p = XMLUtil::SkipWhiteSpace( p, 0 ); if ( *p == 0 ) { break; // don't write to q; this trims the trailing space. } @@ -266,7 +272,7 @@ const char* StrPair::GetStr() _flags ^= NEEDS_FLUSH; if ( _flags ) { - char* p = _start; // the read pointer + const char* p = _start; // the read pointer char* q = _start; // the write pointer while( p < _end ) { @@ -280,7 +286,8 @@ const char* StrPair::GetStr() else { ++p; } - *q++ = LF; + *q = LF; + ++q; } else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) { if ( *(p+1) == CR ) { @@ -289,7 +296,8 @@ const char* StrPair::GetStr() else { ++p; } - *q++ = LF; + *q = LF; + ++q; } else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) { // 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 ) { - 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 ) { if ( TIXML_SSCANF( str, "%d", value ) == 1 ) { @@ -599,6 +614,7 @@ bool XMLUtil::ToFloat( const char* str, float* value ) return false; } + bool XMLUtil::ToDouble( const char* str, double* value ) { 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 ) { TIXMLASSERT( node ); TIXMLASSERT( p ); char* const start = p; - p = XMLUtil::SkipWhiteSpace( p ); + int const startLine = _parseCurLineNum; + p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum ); if( !*p ) { *node = 0; TIXMLASSERT( p ); @@ -639,12 +667,14 @@ char* XMLDocument::Identify( char* p, XMLNode** node ) if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) { TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() ); returnNode = new (_commentPool.Alloc()) XMLDeclaration( this ); + returnNode->_parseLineNum = _parseCurLineNum; returnNode->_memPool = &_commentPool; p += xmlHeaderLen; } else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) { TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() ); returnNode = new (_commentPool.Alloc()) XMLComment( this ); + returnNode->_parseLineNum = _parseCurLineNum; returnNode->_memPool = &_commentPool; p += commentHeaderLen; } @@ -652,6 +682,7 @@ char* XMLDocument::Identify( char* p, XMLNode** node ) TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() ); XMLText* text = new (_textPool.Alloc()) XMLText( this ); returnNode = text; + returnNode->_parseLineNum = _parseCurLineNum; returnNode->_memPool = &_textPool; p += cdataHeaderLen; text->SetCData( true ); @@ -659,12 +690,14 @@ char* XMLDocument::Identify( char* p, XMLNode** node ) else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) { TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() ); returnNode = new (_commentPool.Alloc()) XMLUnknown( this ); + returnNode->_parseLineNum = _parseCurLineNum; returnNode->_memPool = &_commentPool; p += dtdHeaderLen; } else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) { TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() ); returnNode = new (_elementPool.Alloc()) XMLElement( this ); + returnNode->_parseLineNum = _parseCurLineNum; returnNode->_memPool = &_elementPool; p += elementHeaderLen; } @@ -672,7 +705,9 @@ char* XMLDocument::Identify( char* p, XMLNode** node ) TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() ); returnNode = new (_textPool.Alloc()) XMLText( this ); returnNode->_memPool = &_textPool; + returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character p = start; // Back it up, all the text counts. + _parseCurLineNum = startLine; } TIXMLASSERT( returnNode ); @@ -701,8 +736,10 @@ bool XMLDocument::Accept( XMLVisitor* visitor ) const XMLNode::XMLNode( XMLDocument* doc ) : _document( doc ), _parent( 0 ), + _parseLineNum( 0 ), _firstChild( 0 ), _lastChild( 0 ), _prev( 0 ), _next( 0 ), + _userData( 0 ), _memPool( 0 ) { } @@ -718,7 +755,7 @@ XMLNode::~XMLNode() 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() ) return 0; return _value.GetStr(); @@ -739,11 +776,7 @@ void XMLNode::DeleteChildren() { while( _firstChild ) { TIXMLASSERT( _lastChild ); - TIXMLASSERT( _firstChild->_document == _document ); - XMLNode* node = _firstChild; - Unlink( node ); - - DeleteNode( node ); + DeleteChild( _firstChild ); } _firstChild = _lastChild = 0; } @@ -876,11 +909,9 @@ XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis ) const XMLElement* XMLNode::FirstChildElement( const char* name ) const { for( const XMLNode* node = _firstChild; node; node = node->_next ) { - const XMLElement* element = node->ToElement(); + const XMLElement* element = node->ToElementWithName( name ); if ( element ) { - if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) { - return element; - } + return element; } } return 0; @@ -890,11 +921,9 @@ const XMLElement* XMLNode::FirstChildElement( const char* name ) const const XMLElement* XMLNode::LastChildElement( const char* name ) const { for( const XMLNode* node = _lastChild; node; node = node->_prev ) { - const XMLElement* element = node->ToElement(); + const XMLElement* element = node->ToElementWithName( name ); if ( element ) { - if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) { - return element; - } + return element; } } return 0; @@ -904,9 +933,8 @@ const XMLElement* XMLNode::LastChildElement( const char* name ) const const XMLElement* XMLNode::NextSiblingElement( const char* name ) const { for( const XMLNode* node = _next; node; node = node->_next ) { - const XMLElement* element = node->ToElement(); - if ( element - && (!name || XMLUtil::StringEqual( name, element->Name() ))) { + const XMLElement* element = node->ToElementWithName( name ); + if ( element ) { return element; } } @@ -917,9 +945,8 @@ const XMLElement* XMLNode::NextSiblingElement( const char* name ) const const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const { for( const XMLNode* node = _prev; node; node = node->_prev ) { - const XMLElement* element = node->ToElement(); - if ( element - && (!name || XMLUtil::StringEqual( name, element->Name() ))) { + const XMLElement* element = node->ToElementWithName( name ); + if ( 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" // it is a pretty simple flat list: @@ -950,29 +977,42 @@ char* XMLNode::ParseDeep( char* p, StrPair* parentEnd ) XMLNode* node = 0; p = _document->Identify( p, &node ); + TIXMLASSERT( p ); if ( node == 0 ) { break; } + int initialLineNum = node->_parseLineNum; + StrPair endTag; - p = node->ParseDeep( p, &endTag ); + p = node->ParseDeep( p, &endTag, curLineNumPtr ); if ( !p ) { DeleteNode( node ); if ( !_document->Error() ) { - _document->SetError( XML_ERROR_PARSING, 0, 0 ); + _document->SetError( XML_ERROR_PARSING, 0, 0, initialLineNum); } 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 ); + // Declarations are only allowed at document level + bool wellLocated = ( ToDocument() != 0 ); + if ( wellLocated ) { + // Multiple declarations are allowed but all declarations + // must occur before anything else + for ( const XMLNode* existingNode = _document->FirstChild(); existingNode; existingNode = existingNode->NextSibling() ) { + if ( !existingNode->ToDeclaration() ) { + wellLocated = false; break; + } } + } + if ( !wellLocated ) { + _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0, initialLineNum); + DeleteNode( node ); + break; + } } XMLElement* ele = node->ToElement(); @@ -1004,7 +1044,7 @@ char* XMLNode::ParseDeep( char* p, StrPair* parentEnd ) } } if ( mismatch ) { - _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0 ); + _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0, initialLineNum); DeleteNode( node ); break; } @@ -1035,14 +1075,29 @@ void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const 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 ---------- // -char* XMLText::ParseDeep( char* p, StrPair* ) +char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr ) { const char* start = p; if ( this->CData() ) { - p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION ); + p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr ); if ( !p ) { - _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 ); + _document->SetError( XML_ERROR_PARSING_CDATA, start, 0, _parseLineNum ); } return p; } @@ -1052,12 +1107,12 @@ char* XMLText::ParseDeep( char* p, StrPair* ) flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING; } - p = _value.ParseText( p, "<", flags ); + p = _value.ParseText( p, "<", flags, curLineNumPtr ); if ( p && *p ) { return p-1; } if ( !p ) { - _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 ); + _document->SetError( XML_ERROR_PARSING_TEXT, start, 0, _parseLineNum ); } } 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. const char* start = p; - p = _value.ParseText( p, "-->", StrPair::COMMENT ); + p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr ); if ( p == 0 ) { - _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 ); + _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0, _parseLineNum ); } 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. const char* start = p; - p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION ); + p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr ); if ( p == 0 ) { - _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 ); + _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0, _parseLineNum ); } 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. const char* start = p; - p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION ); + p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr ); if ( !p ) { - _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 ); + _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0, _parseLineNum ); } return p; } @@ -1249,7 +1304,7 @@ const char* XMLAttribute::Value() const 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 p = _name.ParseName( p ); @@ -1258,13 +1313,13 @@ char* XMLAttribute::ParseDeep( char* p, bool processEntities ) } // Skip white space before = - p = XMLUtil::SkipWhiteSpace( p ); + p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr ); if ( *p != '=' ) { return 0; } ++p; // move up to opening quote - p = XMLUtil::SkipWhiteSpace( p ); + p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr ); if ( *p != '\"' && *p != '\'' ) { return 0; } @@ -1272,7 +1327,7 @@ char* XMLAttribute::ParseDeep( char* p, bool processEntities ) char endTag[2] = { *p, 0 }; ++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; } @@ -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 { 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 ) { char buf[BUF_SIZE]; @@ -1413,6 +1486,47 @@ const char* XMLElement::Attribute( const char* name, const char* value ) const 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 { @@ -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]; 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 { if ( FirstChild() && FirstChild()->ToText() ) { @@ -1538,6 +1673,47 @@ XMLError XMLElement::QueryFloatText( float* fval ) const 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 ) @@ -1552,17 +1728,17 @@ XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name ) } } if ( !attrib ) { - TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() ); - attrib = new (_document->_attributePool.Alloc() ) XMLAttribute(); - attrib->_memPool = &_document->_attributePool; + attrib = CreateAttribute(); + TIXMLASSERT( attrib ); if ( last ) { + TIXMLASSERT( last->_next == 0 ); last->_next = attrib; } else { + TIXMLASSERT( _rootAttribute == 0 ); _rootAttribute = attrib; } attrib->SetName( name ); - attrib->_memPool->SetTracked(); // always created and linked. } 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; XMLAttribute* prevAttribute = 0; // Read the attributes. while( p ) { - p = XMLUtil::SkipWhiteSpace( p ); + p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr ); if ( !(*p) ) { - _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() ); + _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name(), _parseLineNum ); return 0; } // attribute. if (XMLUtil::IsNameStartChar( *p ) ) { - TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() ); - XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute(); - attrib->_memPool = &_document->_attributePool; - attrib->_memPool->SetTracked(); + XMLAttribute* attrib = CreateAttribute(); + TIXMLASSERT( attrib ); + attrib->_parseLineNum = _document->_parseCurLineNum; - p = attrib->ParseDeep( p, _document->ProcessEntities() ); + int attrLineNum = attrib->_parseLineNum; + + p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr ); if ( !p || Attribute( attrib->Name() ) ) { DeleteAttribute( attrib ); - _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p ); + _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p, attrLineNum ); return 0; } // 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 // now, may reconsider in the future. if ( prevAttribute ) { + TIXMLASSERT( prevAttribute->_next == 0 ); prevAttribute->_next = attrib; } else { + TIXMLASSERT( _rootAttribute == 0 ); _rootAttribute = attrib; } prevAttribute = attrib; @@ -1637,7 +1816,7 @@ char* XMLElement::ParseAttributes( char* p ) return p+2; // done; sealed element. } else { - _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p ); + _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p, _parseLineNum ); return 0; } } @@ -1654,14 +1833,23 @@ void XMLElement::DeleteAttribute( XMLAttribute* 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; +} + // // // foobar // -char* XMLElement::ParseDeep( char* p, StrPair* strPair ) +char* XMLElement::ParseDeep( char* p, StrPair* strPair, int* curLineNumPtr ) { // Read the element name. - p = XMLUtil::SkipWhiteSpace( p ); + p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr ); // The closing element is the form. It is // parsed just like a regular element then deleted from @@ -1676,12 +1864,12 @@ char* XMLElement::ParseDeep( char* p, StrPair* strPair ) return 0; } - p = ParseAttributes( p ); + p = ParseAttributes( p, curLineNumPtr ); if ( !p || !*p || _closingType ) { return p; } - p = XMLNode::ParseDeep( p, strPair ); + p = XMLNode::ParseDeep( p, strPair, curLineNumPtr ); return p; } @@ -1773,8 +1961,6 @@ XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) : _processEntities( processEntities ), _errorID(XML_SUCCESS), _whitespace( whitespace ), - _errorStr1( 0 ), - _errorStr2( 0 ), _charBuffer( 0 ) { // 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 const bool hadError = Error(); #endif - _errorID = XML_SUCCESS; - _errorStr1 = 0; - _errorStr2 = 0; + ClearError(); delete [] _charBuffer; _charBuffer = 0; @@ -1908,7 +2092,7 @@ XMLError XMLDocument::LoadFile( const char* filename ) Clear(); FILE* fp = callfopen( filename, "rb" ); if ( !fp ) { - SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 ); + SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0, 0 ); return _errorID; } LoadFile( fp ); @@ -1932,10 +2116,12 @@ struct LongFitsIntoSizeTMinusOne { }; template <> -bool LongFitsIntoSizeTMinusOne::Fits( unsigned long /*value*/ ) -{ - return true; -} +struct LongFitsIntoSizeTMinusOne { + static bool Fits( unsigned long ) + { + return true; + } +}; XMLError XMLDocument::LoadFile( FILE* fp ) { @@ -1943,7 +2129,7 @@ XMLError XMLDocument::LoadFile( FILE* fp ) fseek( fp, 0, SEEK_SET ); 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; } @@ -1951,19 +2137,19 @@ XMLError XMLDocument::LoadFile( FILE* fp ) const long filelength = ftell( fp ); fseek( fp, 0, SEEK_SET ); if ( filelength == -1L ) { - SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); + SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 ); return _errorID; } TIXMLASSERT( filelength >= 0 ); if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) { // 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; } if ( filelength == 0 ) { - SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); + SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 ); return _errorID; } @@ -1972,7 +2158,7 @@ XMLError XMLDocument::LoadFile( FILE* fp ) _charBuffer = new char[size+1]; size_t read = fread( _charBuffer, 1, size, fp ); if ( read != size ) { - SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); + SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 ); return _errorID; } @@ -1987,7 +2173,7 @@ XMLError XMLDocument::SaveFile( const char* filename, bool compact ) { FILE* fp = callfopen( filename, "w" ); 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; } 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 // for *this* call. - SetError(XML_SUCCESS, 0, 0); + ClearError(); XMLPrinter stream( fp, compact ); Print( &stream ); return _errorID; @@ -2012,7 +2198,7 @@ XMLError XMLDocument::Parse( const char* p, size_t len ) Clear(); if ( len == 0 || !p || !*p ) { - SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); + SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 ); return _errorID; } 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 ); _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 { - TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT ); - const char* errorName = _errorNames[_errorID]; - TIXMLASSERT( errorName && errorName[0] ); - return errorName; + return ErrorIDToName(_errorID); } void XMLDocument::PrintError() const @@ -2073,18 +2271,18 @@ void XMLDocument::PrintError() const char buf1[LEN] = { 0 }; char buf2[LEN] = { 0 }; - if ( _errorStr1 ) { - TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 ); + if ( !_errorStr1.Empty() ) { + TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1.GetStr() ); } - if ( _errorStr2 ) { - TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 ); + if ( !_errorStr2.Empty() ) { + TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2.GetStr() ); } // 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", - static_cast( _errorID ), ErrorName(), buf1, buf2 ); + printf( "XMLDocument error id=%d '%s' str1=%s str2=%s line=%d\n", + static_cast( _errorID ), ErrorName(), buf1, buf2, _errorLineNum ); } } @@ -2092,14 +2290,16 @@ void XMLDocument::Parse() { TIXMLASSERT( NoChildren() ); // Clear() must have been called previously TIXMLASSERT( _charBuffer ); + _parseCurLineNum = 1; + _parseLineNum = 1; char* p = _charBuffer; - p = XMLUtil::SkipWhiteSpace( p ); + p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum ); p = const_cast( XMLUtil::ReadBOM( p, &_writeBOM ) ); if ( !*p ) { - SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); + SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 ); return; } - ParseDeep(p, 0 ); + ParseDeep(p, 0, &_parseCurLineNum ); } 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 # include #endif +#include /* TODO: intern strings instead of allocation. @@ -71,6 +72,8 @@ distribution. # else # define TINYXML2_LIB # endif +#elif __GNUC__ >= 4 +# define TINYXML2_LIB __attribute__((visibility("default"))) #else # define TINYXML2_LIB #endif @@ -95,9 +98,9 @@ distribution. /* Versioning, past 1.0.14: 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_PATCH_VERSION = 0; +static const int TIXML2_PATCH_VERSION = 1; namespace tinyxml2 { @@ -124,18 +127,20 @@ public: NEEDS_NEWLINE_NORMALIZATION = 0x02, 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, - ATTRIBUTE_NAME = 0, - ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION, - ATTRIBUTE_VALUE_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION, - COMMENT = NEEDS_NEWLINE_NORMALIZATION + ATTRIBUTE_NAME = 0, + ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION, + ATTRIBUTE_VALUE_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION, + COMMENT = NEEDS_NEWLINE_NORMALIZATION }; StrPair() : _flags( 0 ), _start( 0 ), _end( 0 ) {} ~StrPair(); void Set( char* start, char* end, int flags ) { + TIXMLASSERT( start ); + TIXMLASSERT( end ); Reset(); _start = start; _end = end; @@ -155,13 +160,13 @@ public: 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 ); void TransferTo( StrPair* other ); + void Reset(); private: - void Reset(); void CollapseWhitespace(); enum { @@ -206,7 +211,8 @@ public: void Push( T t ) { TIXMLASSERT( _size < INT_MAX ); EnsureCapacity( _size+1 ); - _mem[_size++] = t; + _mem[_size] = t; + ++_size; } T* PushArr( int count ) { @@ -220,7 +226,8 @@ public: T Pop() { TIXMLASSERT( _size > 0 ); - return _mem[--_size]; + --_size; + return _mem[_size]; } void PopArr( int count ) { @@ -314,7 +321,7 @@ public: /* Template child class to create pools of the correct type. */ -template< int SIZE > +template< int ITEM_SIZE > class MemPoolT : public MemPool { public: @@ -337,7 +344,7 @@ public: } virtual int ItemSize() const { - return SIZE; + return ITEM_SIZE; } int CurrentAllocs() const { return _currentAllocs; @@ -349,21 +356,23 @@ public: Block* block = new Block(); _blockPtrs.Push( block ); - for( int i=0; ichunk[i].next = &block->chunk[i+1]; + Item* blockItems = block->items; + for( int i = 0; i < ITEMS_PER_BLOCK - 1; ++i ) { + blockItems[i].next = &(blockItems[i + 1]); } - block->chunk[COUNT-1].next = 0; - _root = block->chunk; + blockItems[ITEMS_PER_BLOCK - 1].next = 0; + _root = blockItems; } - void* result = _root; + Item* const result = _root; + TIXMLASSERT( result != 0 ); _root = _root->next; ++_currentAllocs; if ( _currentAllocs > _maxAllocs ) { _maxAllocs = _currentAllocs; } - _nAllocs++; - _nUntracked++; + ++_nAllocs; + ++_nUntracked; return result; } @@ -372,20 +381,21 @@ public: return; } --_currentAllocs; - Chunk* chunk = static_cast( mem ); + Item* item = static_cast( mem ); #ifdef DEBUG - memset( chunk, 0xfe, sizeof(Chunk) ); + memset( item, 0xfe, sizeof( *item ) ); #endif - chunk->next = _root; - _root = chunk; + item->next = _root; + _root = item; } void Trace( const char* name ) { 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() { - _nUntracked--; + --_nUntracked; } int Untracked() const { @@ -401,21 +411,23 @@ public: // 16k: 5200 // 32k: 4300 // 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: MemPoolT( const MemPoolT& ); // not supported void operator=( const MemPoolT& ); // not supported - union Chunk { - Chunk* next; - char mem[SIZE]; + union Item { + Item* next; + char itemData[ITEM_SIZE]; }; struct Block { - Chunk chunk[COUNT]; + Item items[ITEMS_PER_BLOCK]; }; DynArray< Block*, 10 > _blockPtrs; - Chunk* _root; + Item* _root; int _currentAllocs; int _nAllocs; @@ -518,16 +530,20 @@ enum XMLError { class XMLUtil { public: - static const char* SkipWhiteSpace( const char* p ) { + static const char* SkipWhiteSpace( const char* p, int* curLineNumPtr ) { TIXMLASSERT( p ); + while( IsWhiteSpace(*p) ) { + if (curLineNumPtr && *p == '\n') { + ++(*curLineNumPtr); + } ++p; } TIXMLASSERT( p ); return p; } - static char* SkipWhiteSpace( char* p ) { - return const_cast( SkipWhiteSpace( const_cast(p) ) ); + static char* SkipWhiteSpace( char* p, int* curLineNumPtr ) { + return const_cast( SkipWhiteSpace( const_cast(p), curLineNumPtr ) ); } // 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 ) { return true; } + TIXMLASSERT( p ); + TIXMLASSERT( q ); + TIXMLASSERT( 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( float 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 static bool ToInt( const char* str, int* value ); @@ -584,6 +604,7 @@ public: static bool ToBool( const char* str, bool* value ); static bool ToFloat( const char* str, float* 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 ); + /// 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. const XMLNode* Parent() const { return _parent; @@ -854,15 +878,30 @@ public: */ 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: XMLNode( XMLDocument* ); virtual ~XMLNode(); - virtual char* ParseDeep( char*, StrPair* ); + virtual char* ParseDeep( char*, StrPair*, int* ); XMLDocument* _document; XMLNode* _parent; mutable StrPair _value; + int _parseLineNum; XMLNode* _firstChild; XMLNode* _lastChild; @@ -870,11 +909,14 @@ protected: XMLNode* _prev; XMLNode* _next; + void* _userData; + private: MemPool* _memPool; void Unlink( XMLNode* child ); static void DeleteNode( XMLNode* node ); void InsertChildPreamble( XMLNode* insertThis ) const; + const XMLElement* ToElementWithName( const char* name ) const; XMLNode( const XMLNode& ); // not supported XMLNode& operator=( const XMLNode& ); // not supported @@ -922,7 +964,7 @@ protected: XMLText( XMLDocument* doc ) : XMLNode( doc ), _isCData( false ) {} virtual ~XMLText() {} - char* ParseDeep( char*, StrPair* endTag ); + char* ParseDeep( char*, StrPair* endTag, int* curLineNumPtr ); private: bool _isCData; @@ -953,7 +995,7 @@ protected: XMLComment( XMLDocument* doc ); virtual ~XMLComment(); - char* ParseDeep( char*, StrPair* endTag ); + char* ParseDeep( char*, StrPair* endTag, int* curLineNumPtr); private: XMLComment( const XMLComment& ); // not supported @@ -992,7 +1034,7 @@ protected: XMLDeclaration( XMLDocument* doc ); virtual ~XMLDeclaration(); - char* ParseDeep( char*, StrPair* endTag ); + char* ParseDeep( char*, StrPair* endTag, int* curLineNumPtr ); private: XMLDeclaration( const XMLDeclaration& ); // not supported @@ -1027,7 +1069,7 @@ protected: XMLUnknown( XMLDocument* doc ); virtual ~XMLUnknown(); - char* ParseDeep( char*, StrPair* endTag ); + char* ParseDeep( char*, StrPair* endTag, int* curLineNumPtr ); private: XMLUnknown( const XMLUnknown& ); // not supported @@ -1052,6 +1094,9 @@ public: /// The value of the attribute. 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. const XMLAttribute* Next() const { return _next; @@ -1061,11 +1106,18 @@ public: If the value isn't an integer, 0 will be returned. There is no error checking; use QueryIntValue() if you need error checking. */ - int IntValue() const { - int i=0; - QueryIntValue( &i ); - return i; - } + int IntValue() const { + int i = 0; + QueryIntValue(&i); + return i; + } + + int64_t Int64Value() const { + int64_t i = 0; + QueryInt64Value(&i); + return i; + } + /// Query as an unsigned integer. See IntValue() unsigned UnsignedValue() const { unsigned i=0; @@ -1092,13 +1144,15 @@ public: } /** 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. */ XMLError QueryIntValue( int* value ) const; /// See QueryIntValue XMLError QueryUnsignedValue( unsigned int* value ) const; - /// See QueryIntValue + /// See QueryIntValue + XMLError QueryInt64Value(int64_t* value) const; + /// See QueryIntValue XMLError QueryBoolValue( bool* value ) const; /// See QueryIntValue XMLError QueryDoubleValue( double* value ) const; @@ -1111,7 +1165,9 @@ public: void SetAttribute( int value ); /// Set the attribute to 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 ); /// Set the attribute to value. void SetAttribute( double value ); @@ -1128,10 +1184,11 @@ private: void operator=( const XMLAttribute& ); // not supported void SetName( const char* name ); - char* ParseDeep( char* p, bool processEntities ); + char* ParseDeep( char* p, bool processEntities, int* curLineNumPtr ); mutable StrPair _name; mutable StrPair _value; + int _parseLineNum; XMLAttribute* _next; MemPool* _memPool; }; @@ -1188,42 +1245,25 @@ public: const char* Attribute( const char* name, const char* value=0 ) const; /** Given an attribute name, IntAttribute() returns the value - of the attribute interpreted as an integer. 0 will be - returned if there is an error. For a method with error - checking, see QueryIntAttribute() + of the attribute interpreted as an integer. The default + value will be returned if the attribute isn't present, + or if there is an error. (For a method with error + checking, see QueryIntAttribute()). */ - int IntAttribute( const char* name ) const { - int i=0; - QueryIntAttribute( name, &i ); - return i; - } + int IntAttribute(const char* name, int defaultValue = 0) const; /// See IntAttribute() - unsigned UnsignedAttribute( const char* name ) const { - unsigned i=0; - QueryUnsignedAttribute( name, &i ); - return i; - } + unsigned UnsignedAttribute(const char* name, unsigned defaultValue = 0) const; + /// See IntAttribute() + int64_t Int64Attribute(const char* name, int64_t defaultValue = 0) const; + /// See IntAttribute() + bool BoolAttribute(const char* name, bool defaultValue = false) const; /// See IntAttribute() - bool BoolAttribute( const char* name ) const { - bool b=false; - QueryBoolAttribute( name, &b ); - return b; - } + double DoubleAttribute(const char* name, double defaultValue = 0) const; /// See IntAttribute() - double DoubleAttribute( const char* name ) 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; - } + float FloatAttribute(const char* name, float defaultValue = 0) const; /** 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 doesn't exist. If successful, the result of the conversion will be written to 'value'. If not successful, nothing will @@ -1242,7 +1282,8 @@ public: } return a->QueryIntValue( value ); } - /// See QueryIntAttribute() + + /// See QueryIntAttribute() XMLError QueryUnsignedAttribute( const char* name, unsigned int* value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) { @@ -1250,7 +1291,17 @@ public: } 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 { const XMLAttribute* a = FindAttribute( name ); if ( !a ) { @@ -1277,7 +1328,7 @@ public: /** 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 doesn't exist. It is overloaded for the primitive types, and is a generally more convenient replacement of @@ -1301,6 +1352,10 @@ public: 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 { return QueryBoolAttribute( name, value ); } @@ -1328,7 +1383,14 @@ public: XMLAttribute* a = FindOrCreateAttribute( name ); 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 ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); @@ -1425,7 +1487,9 @@ public: void SetText( int value ); /// Convenience method for setting text inside an element. See SetText() for important limitations. 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 ); /// Convenience method for setting text inside an element. See SetText() for important limitations. void SetText( double value ); @@ -1461,13 +1525,28 @@ public: XMLError QueryIntText( int* ival ) const; /// See QueryIntText() XMLError QueryUnsignedText( unsigned* uval ) const; - /// See QueryIntText() + /// See QueryIntText() + XMLError QueryInt64Text(int64_t* uval) const; + /// See QueryIntText() XMLError QueryBoolText( bool* bval ) const; /// See QueryIntText() XMLError QueryDoubleText( double* dval ) const; /// See QueryIntText() 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: enum { OPEN, // @@ -1481,7 +1560,7 @@ public: virtual bool ShallowEqual( const XMLNode* compare ) const; protected: - char* ParseDeep( char* p, StrPair* endTag ); + char* ParseDeep( char* p, StrPair* endTag, int* curLineNumPtr ); private: XMLElement( XMLDocument* doc ); @@ -1494,8 +1573,9 @@ private: } XMLAttribute* FindOrCreateAttribute( const char* name ); //void LinkAttribute( XMLAttribute* attrib ); - char* ParseAttributes( char* p ); + char* ParseAttributes( char* p, int* curLineNumPtr ); static void DeleteAttribute( XMLAttribute* attribute ); + XMLAttribute* CreateAttribute(); enum { BUF_SIZE = 200 }; int _closingType; @@ -1536,7 +1616,7 @@ public: /** 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. You may optionally pass in the 'nBytes', which is @@ -1548,7 +1628,7 @@ public: /** Load an XML file from disk. - Returns XML_NO_ERROR (0) on success, or + Returns XML_SUCCESS (0) on success, or an errorID. */ XMLError LoadFile( const char* filename ); @@ -1561,14 +1641,14 @@ public: not text in order for TinyXML-2 to correctly do newline normalization. - Returns XML_NO_ERROR (0) on success, or + Returns XML_SUCCESS (0) on success, or an errorID. */ XMLError LoadFile( FILE* ); /** Save the XML file to disk. - Returns XML_NO_ERROR (0) on success, or + Returns XML_SUCCESS (0) on success, or an errorID. */ XMLError SaveFile( const char* filename, bool compact = false ); @@ -1577,7 +1657,7 @@ public: Save the XML file to disk. You are responsible for providing and closing the FILE*. - Returns XML_NO_ERROR (0) on success, or + Returns XML_SUCCESS (0) on success, or an errorID. */ XMLError SaveFile( FILE* fp, bool compact = false ); @@ -1671,7 +1751,11 @@ public: */ 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. bool Error() const { @@ -1682,14 +1766,20 @@ public: return _errorID; } const char* ErrorName() const; + static const char* ErrorIDToName(XMLError errorID); /// Return a possibly helpful diagnostic location or string. const char* GetErrorStr1() const { - return _errorStr1; + return _errorStr1.GetStr(); } /// Return a possibly helpful secondary diagnostic location or string. 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. void PrintError() const; @@ -1711,13 +1801,15 @@ private: XMLDocument( const XMLDocument& ); // not supported void operator=( const XMLDocument& ); // not supported - bool _writeBOM; - bool _processEntities; - XMLError _errorID; - Whitespace _whitespace; - const char* _errorStr1; - const char* _errorStr2; - char* _charBuffer; + bool _writeBOM; + bool _processEntities; + XMLError _errorID; + Whitespace _whitespace; + mutable StrPair _errorStr1; + mutable StrPair _errorStr2; + int _errorLineNum; + char* _charBuffer; + int _parseCurLineNum; MemPoolT< sizeof(XMLElement) > _elementPool; MemPoolT< sizeof(XMLAttribute) > _attributePool; @@ -1845,19 +1937,19 @@ public: } /// Safe cast to XMLElement. This can return null. XMLElement* ToElement() { - return ( ( _node == 0 ) ? 0 : _node->ToElement() ); + return ( _node ? _node->ToElement() : 0 ); } /// Safe cast to XMLText. This can return null. XMLText* ToText() { - return ( ( _node == 0 ) ? 0 : _node->ToText() ); + return ( _node ? _node->ToText() : 0 ); } /// Safe cast to XMLUnknown. This can return null. XMLUnknown* ToUnknown() { - return ( ( _node == 0 ) ? 0 : _node->ToUnknown() ); + return ( _node ? _node->ToUnknown() : 0 ); } /// Safe cast to XMLDeclaration. This can return null. XMLDeclaration* ToDeclaration() { - return ( ( _node == 0 ) ? 0 : _node->ToDeclaration() ); + return ( _node ? _node->ToDeclaration() : 0 ); } private: @@ -1917,16 +2009,16 @@ public: return _node; } const XMLElement* ToElement() const { - return ( ( _node == 0 ) ? 0 : _node->ToElement() ); + return ( _node ? _node->ToElement() : 0 ); } const XMLText* ToText() const { - return ( ( _node == 0 ) ? 0 : _node->ToText() ); + return ( _node ? _node->ToText() : 0 ); } const XMLUnknown* ToUnknown() const { - return ( ( _node == 0 ) ? 0 : _node->ToUnknown() ); + return ( _node ? _node->ToUnknown() : 0 ); } const XMLDeclaration* ToDeclaration() const { - return ( ( _node == 0 ) ? 0 : _node->ToDeclaration() ); + return ( _node ? _node->ToDeclaration() : 0 ); } private: @@ -1998,7 +2090,8 @@ public: void PushAttribute( const char* name, const char* value ); void PushAttribute( const char* name, int 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 ); /// If streaming, close the Element. virtual void CloseElement( bool compactMode=false ); @@ -2009,7 +2102,9 @@ public: void PushText( int value ); /// Add a text node from an unsigned. 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 ); /// Add a text node from a float. void PushText( float value );