diff --git a/tinyxml2.cpp b/tinyxml2.cpp index 6d00922..d147ffe 100755 --- a/tinyxml2.cpp +++ b/tinyxml2.cpp @@ -165,6 +165,7 @@ void StrPair::TransferTo( StrPair* other ) _end = 0; } + void StrPair::Reset() { if ( _flags & NEEDS_DELETE ) { @@ -1019,7 +1020,7 @@ char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) if ( !p ) { DeleteNode( node ); if ( !_document->Error() ) { - _document->SetError( XML_ERROR_PARSING, 0, 0, initialLineNum); + _document->SetError( XML_ERROR_PARSING, initialLineNum, 0); } break; } @@ -1039,7 +1040,7 @@ char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) } } if ( !wellLocated ) { - _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0, initialLineNum); + _document->SetError( XML_ERROR_PARSING_DECLARATION, initialLineNum, "XMLDeclaration value=%s", decl->Value()); DeleteNode( node ); break; } @@ -1074,7 +1075,7 @@ char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) } } if ( mismatch ) { - _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0, initialLineNum); + _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, initialLineNum, "XMLElement name=%s", ele->Name()); DeleteNode( node ); break; } @@ -1131,11 +1132,10 @@ const XMLElement* XMLNode::ToElementWithName( const char* name ) const // --------- XMLText ---------- // char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr ) { - const char* start = p; if ( this->CData() ) { p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr ); if ( !p ) { - _document->SetError( XML_ERROR_PARSING_CDATA, start, 0, _parseLineNum ); + _document->SetError( XML_ERROR_PARSING_CDATA, _parseLineNum, 0 ); } return p; } @@ -1150,7 +1150,7 @@ char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr ) return p-1; } if ( !p ) { - _document->SetError( XML_ERROR_PARSING_TEXT, start, 0, _parseLineNum ); + _document->SetError( XML_ERROR_PARSING_TEXT, _parseLineNum, 0 ); } } return 0; @@ -1198,10 +1198,9 @@ XMLComment::~XMLComment() char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr ) { // Comment parses as text. - const char* start = p; p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr ); if ( p == 0 ) { - _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0, _parseLineNum ); + _document->SetError( XML_ERROR_PARSING_COMMENT, _parseLineNum, 0 ); } return p; } @@ -1248,10 +1247,9 @@ XMLDeclaration::~XMLDeclaration() char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr ) { // Declaration parses as text. - const char* start = p; p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr ); if ( p == 0 ) { - _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0, _parseLineNum ); + _document->SetError( XML_ERROR_PARSING_DECLARATION, _parseLineNum, 0 ); } return p; } @@ -1297,11 +1295,9 @@ XMLUnknown::~XMLUnknown() char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr ) { // Unknown parses as text. - const char* start = p; - p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr ); if ( !p ) { - _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0, _parseLineNum ); + _document->SetError( XML_ERROR_PARSING_UNKNOWN, _parseLineNum, 0 ); } return p; } @@ -1804,14 +1800,13 @@ void XMLElement::DeleteAttribute( const char* name ) char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr ) { - const char* start = p; XMLAttribute* prevAttribute = 0; // Read the attributes. while( p ) { p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr ); if ( !(*p) ) { - _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name(), _parseLineNum ); + _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, "XMLElement name=%s", Name() ); return 0; } @@ -1826,7 +1821,7 @@ char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr ) p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr ); if ( !p || Attribute( attrib->Name() ) ) { DeleteAttribute( attrib ); - _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p, attrLineNum ); + _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, attrLineNum, "XMLElement name=%s", Name() ); return 0; } // There is a minor bug here: if the attribute in the source xml @@ -1855,7 +1850,7 @@ char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr ) return p+2; // done; sealed element. } else { - _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p, _parseLineNum ); + _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, 0 ); return 0; } } @@ -2001,8 +1996,7 @@ XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) : _processEntities( processEntities ), _errorID(XML_SUCCESS), _whitespaceMode( whitespaceMode ), - _errorStr1(), - _errorStr2(), + _errorStr(), _errorLineNum( 0 ), _charBuffer( 0 ), _parseCurLineNum( 0 ), @@ -2160,7 +2154,7 @@ XMLError XMLDocument::LoadFile( const char* filename ) Clear(); FILE* fp = callfopen( filename, "rb" ); if ( !fp ) { - SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0, 0 ); + SetError( XML_ERROR_FILE_NOT_FOUND, 0, "filename=%s", filename ? filename : ""); return _errorID; } LoadFile( fp ); @@ -2197,7 +2191,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, 0 ); + SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); return _errorID; } @@ -2205,19 +2199,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, 0 ); + SetError( XML_ERROR_FILE_READ_ERROR, 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, 0 ); + SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); return _errorID; } if ( filelength == 0 ) { - SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 ); + SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); return _errorID; } @@ -2226,7 +2220,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, 0 ); + SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); return _errorID; } @@ -2241,7 +2235,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, 0 ); + SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=%s", filename ? filename : ""); return _errorID; } SaveFile(fp, compact); @@ -2266,7 +2260,7 @@ XMLError XMLDocument::Parse( const char* p, size_t len ) Clear(); if ( len == 0 || !p || !*p ) { - SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 ); + SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); return _errorID; } if ( len == (size_t)(-1) ) { @@ -2304,21 +2298,30 @@ void XMLDocument::Print( XMLPrinter* streamer ) const } -void XMLDocument::SetError( XMLError error, const char* str1, const char* str2, int lineNum ) +void XMLDocument::SetError( XMLError error, int lineNum, const char* format, ... ) { TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT ); _errorID = error; - - _errorStr1.Reset(); - _errorStr2.Reset(); _errorLineNum = lineNum; + _errorStr.Reset(); - if (str1) - _errorStr1.SetStr(str1); - if (str2) - _errorStr2.SetStr(str2); + if (format) { + size_t BUFFER_SIZE = 1000; + char* buffer = new char[BUFFER_SIZE]; + TIXML_SNPRINTF(buffer, BUFFER_SIZE, "Error=%s ErrorID=%d (0x%x) Line number=%d: ", ErrorIDToName(error), int(error), int(error), lineNum); + size_t len = strlen(buffer); + + va_list va; + va_start( va, format ); + TIXML_VSNPRINTF( buffer + len, BUFFER_SIZE - len, format, va ); + va_end( va ); + + _errorStr.SetStr(buffer); + delete [] buffer; + } } + /*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID) { TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT ); @@ -2327,14 +2330,15 @@ void XMLDocument::SetError( XMLError error, const char* str1, const char* str2, return errorName; } -const char* XMLDocument::GetErrorStr1() const +const char* XMLDocument::ErrorStr() const { - return _errorStr1.GetStr(); + return _errorStr.Empty() ? "" : _errorStr.GetStr(); } -const char* XMLDocument::GetErrorStr2() const + +void XMLDocument::PrintError() const { - return _errorStr2.GetStr(); + printf("%s\n", ErrorStr()); } const char* XMLDocument::ErrorName() const @@ -2342,28 +2346,6 @@ const char* XMLDocument::ErrorName() const return ErrorIDToName(_errorID); } -void XMLDocument::PrintError() const -{ - if ( Error() ) { - static const int LEN = 20; - char buf1[LEN] = { 0 }; - char buf2[LEN] = { 0 }; - - if ( !_errorStr1.Empty() ) { - TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1.GetStr() ); - } - 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 line=%d\n", - static_cast( _errorID ), ErrorName(), buf1, buf2, _errorLineNum ); - } -} - void XMLDocument::Parse() { TIXMLASSERT( NoChildren() ); // Clear() must have been called previously @@ -2374,7 +2356,7 @@ void XMLDocument::Parse() p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum ); p = const_cast( XMLUtil::ReadBOM( p, &_writeBOM ) ); if ( !*p ) { - SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 ); + SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); return; } ParseDeep(p, 0, &_parseCurLineNum ); diff --git a/tinyxml2.h b/tinyxml2.h index 316f2ba..1331615 100755 --- a/tinyxml2.h +++ b/tinyxml2.h @@ -1635,6 +1635,13 @@ enum Whitespace { class TINYXML2_LIB XMLDocument : public XMLNode { friend class XMLElement; + // Gives access to SetError, but over-access for everything else. + // Wishing C++ had "internal" scope. + friend class XMLNode; + friend class XMLText; + friend class XMLComment; + friend class XMLDeclaration; + friend class XMLUnknown; public: /// constructor XMLDocument( bool processEntities = true, Whitespace whitespaceMode = PRESERVE_WHITESPACE ); @@ -1786,10 +1793,8 @@ public: */ void DeleteNode( XMLNode* node ); - void SetError( XMLError error, const char* str1, const char* str2, int lineNum ); - void ClearError() { - SetError(XML_SUCCESS, 0, 0, 0); + SetError(XML_SUCCESS, 0, 0); } /// Return true if there was an error parsing the document. @@ -1803,19 +1808,19 @@ public: const char* ErrorName() const; static const char* ErrorIDToName(XMLError errorID); - /// Return a possibly helpful diagnostic location or string. - const char* GetErrorStr1() const; + /** Returns a "long form" error description. A hopefully helpful + diagnostic with location, line number, and/or additional info. + */ + const char* ErrorStr() const; - /// Return a possibly helpful secondary diagnostic location or string. - const char* GetErrorStr2() const; + /// A (trivial) utility function that prints the ErrorStr() to stdout. + void PrintError() const; /// Return the line where the error occured, or zero if unknown. - int GetErrorLineNum() const + int ErrorLineNum() const { return _errorLineNum; } - /// If there is an error, print it to stdout. - void PrintError() const; /// Clear the document, resetting it to the initial state. void Clear(); @@ -1850,8 +1855,7 @@ private: bool _processEntities; XMLError _errorID; Whitespace _whitespaceMode; - mutable StrPair _errorStr1; - mutable StrPair _errorStr2; + mutable StrPair _errorStr; int _errorLineNum; char* _charBuffer; int _parseCurLineNum; @@ -1872,6 +1876,8 @@ private: void Parse(); + void SetError( XMLError error, int lineNum, const char* format, ... ); + template NodeType* CreateUnlinkedNode( MemPoolT& pool ); }; diff --git a/xmltest.cpp b/xmltest.cpp index 111db88..91494ec 100644 --- a/xmltest.cpp +++ b/xmltest.cpp @@ -1962,11 +1962,9 @@ int main( int argc, const char ** argv ) XMLDocument doc; for( int i = 0; i < XML_ERROR_COUNT; i++ ) { const XMLError error = static_cast(i); - doc.SetError( error, 0, 0, 0 ); - XMLTest( "ErrorID() after SetError()", error, doc.ErrorID() ); - const char* name = doc.ErrorName(); - XMLTest( "ErrorName() after SetError()", true, name != 0 ); - XMLTest( "ErrorName() after SetError()", true, strlen(name) > 0 ); + const char* name = XMLDocument::ErrorIDToName(error); + XMLTest( "ErrorName() after ClearError()", true, name != 0 ); + XMLTest( "ErrorName() after ClearError()", true, strlen(name) > 0 ); } } @@ -2077,7 +2075,7 @@ int main( int argc, const char ** argv ) XMLTest(testString, parseError, doc.ErrorID()); XMLTest(testString, true, doc.Error()); XMLTest(testString, expected_error, parseError); - XMLTest(testString, expectedLine, doc.GetErrorLineNum()); + XMLTest(testString, expectedLine, doc.ErrorLineNum()); }; void TestStringLines(const char *testString, const char *docStr, const char *expectedLines) @@ -2196,6 +2194,18 @@ int main( int argc, const char ** argv ) "D01L01E02E03A03A03T03E04A04A04T04E05A05A05T05E06A06A06T06E07A07A07T07E08A08A08T08E09T09E10T10"); } + { + const char* xml = "Text"; + XMLDocument doc; + doc.Parse(xml); + XMLTest("Test mismatched elements.", true, doc.Error()); + XMLTest("Test mismatched elements.", XML_ERROR_MISMATCHED_ELEMENT, doc.ErrorID()); + // For now just make sure calls work & doesn't crash. + // May solidify the error output in the future. + printf("%s\n", doc.ErrorStr()); + doc.PrintError(); + } + // ----------- Performance tracking -------------- { #if defined( _MSC_VER )