Use TinyXML to write XML files

This commit is contained in:
PKEuS 2013-08-07 16:30:55 +02:00
parent a9a5dc0354
commit 758d68519d
4 changed files with 69 additions and 88 deletions

View File

@ -1729,11 +1729,11 @@ void XMLDocument::PrintError() const
} }
XMLPrinter::XMLPrinter( FILE* file, bool compact ) : XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
_elementJustOpened( false ), _elementJustOpened( false ),
_firstElement( true ), _firstElement( true ),
_fp( file ), _fp( file ),
_depth( 0 ), _depth( depth ),
_textDepth( -1 ), _textDepth( -1 ),
_processEntities( true ), _processEntities( true ),
_compactMode( compact ) _compactMode( compact )
@ -1840,7 +1840,7 @@ void XMLPrinter::PrintString( const char* p, bool restricted )
void XMLPrinter::PushHeader( bool writeBOM, bool writeDec ) void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
{ {
if ( writeBOM ) { if ( writeBOM ) {
static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 }; static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
Print( "%s", bom ); Print( "%s", bom );
} }
if ( writeDec ) { if ( writeDec ) {
@ -1858,6 +1858,8 @@ void XMLPrinter::OpenElement( const char* name )
if ( _textDepth < 0 && !_firstElement && !_compactMode ) { if ( _textDepth < 0 && !_firstElement && !_compactMode ) {
Print( "\n" ); Print( "\n" );
}
if ( !_compactMode ) {
PrintSpace( _depth ); PrintSpace( _depth );
} }

View File

@ -14,6 +14,7 @@ not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation software in a product, an acknowledgment in the product documentation
would be appreciated but is not required. would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and 2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software. must not be misrepresented as being the original software.
@ -125,11 +126,9 @@ class XMLDocument;
class XMLElement; class XMLElement;
class XMLAttribute; class XMLAttribute;
class XMLComment; class XMLComment;
class XMLNode;
class XMLText; class XMLText;
class XMLDeclaration; class XMLDeclaration;
class XMLUnknown; class XMLUnknown;
class XMLPrinter; class XMLPrinter;
/* /*
@ -144,14 +143,14 @@ public:
enum { enum {
NEEDS_ENTITY_PROCESSING = 0x01, NEEDS_ENTITY_PROCESSING = 0x01,
NEEDS_NEWLINE_NORMALIZATION = 0x02, NEEDS_NEWLINE_NORMALIZATION = 0x02,
COLLAPSE_WHITESPACE = 0x04, COLLAPSE_WHITESPACE = 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 ) {}
@ -1884,7 +1883,7 @@ public:
If 'compact' is set to true, then output is created If 'compact' is set to true, then output is created
with only required whitespace and newlines. with only required whitespace and newlines.
*/ */
XMLPrinter( FILE* file=0, bool compact = false ); XMLPrinter( FILE* file=0, bool compact = false, int depth = 0 );
~XMLPrinter() {} ~XMLPrinter() {}
/** If streaming, write the BOM and declaration. */ /** If streaming, write the BOM and declaration. */

View File

@ -22,6 +22,8 @@
#include "tokenlist.h" #include "tokenlist.h"
#include "token.h" #include "token.h"
#include <tinyxml2.h>
#include <cassert> #include <cassert>
#include <sstream> #include <sstream>
#include <vector> #include <vector>
@ -177,95 +179,73 @@ std::string ErrorLogger::ErrorMessage::getXMLHeader(int xml_version)
{ {
// xml_version 1 is the default xml format // xml_version 1 is the default xml format
tinyxml2::XMLPrinter printer;
// standard xml header // standard xml header
std::ostringstream ostr; printer.PushDeclaration("xml version=\"1.0\" encoding=\"UTF-8\"");
ostr << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
// version 1 header
if (xml_version <= 1) {
ostr << "<results>";
}
// header
printer.OpenElement("results");
// version 2 header // version 2 header
else { if (xml_version == 2) {
ostr << "<results version=\"" << xml_version << "\">\n"; printer.PushAttribute("version", xml_version);
ostr << " <cppcheck version=\"" << CppCheck::version() << "\"/>\n"; printer.OpenElement("cppcheck");
ostr << " <errors>"; printer.PushAttribute("version", CppCheck::version());
printer.CloseElement();
printer.OpenElement("errors");
} }
return ostr.str(); return std::string(printer.CStr()) + '>';
} }
std::string ErrorLogger::ErrorMessage::getXMLFooter(int xml_version) std::string ErrorLogger::ErrorMessage::getXMLFooter(int xml_version)
{ {
return (xml_version<=1) ? "</results>" : " </errors>\n</results>"; return (xml_version<=1) ? "</results>" : " </errors>\n</results>";
}
static std::string stringToXml(std::string s)
{
// convert a string so it can be save as xml attribute data
std::string::size_type pos = 0;
while ((pos = s.find_first_of("<>&\"\n", pos)) != std::string::npos) {
if (s[pos] == '<')
s.insert(pos + 1, "&lt;");
else if (s[pos] == '>')
s.insert(pos + 1, "&gt;");
else if (s[pos] == '&')
s.insert(pos + 1, "&amp;");
else if (s[pos] == '"')
s.insert(pos + 1, "&quot;");
else if (s[pos] == '\n')
s.insert(pos + 1, "&#xa;");
s.erase(pos, 1);
++pos;
}
return s;
} }
std::string ErrorLogger::ErrorMessage::toXML(bool verbose, int version) const std::string ErrorLogger::ErrorMessage::toXML(bool verbose, int version) const
{ {
// Save this ErrorMessage as an XML element
std::ostringstream xml;
// The default xml format // The default xml format
if (version == 1) { if (version == 1) {
// No inconclusive messages in the xml version 1 // No inconclusive messages in the xml version 1
if (_inconclusive) if (_inconclusive)
return ""; return "";
xml << "<error"; tinyxml2::XMLPrinter printer(0, false, 1);
printer.OpenElement("error");
if (!_callStack.empty()) { if (!_callStack.empty()) {
xml << " file=\"" << stringToXml(_callStack.back().getfile()) << "\""; printer.PushAttribute("file", _callStack.back().getfile().c_str());
xml << " line=\"" << _callStack.back().line << "\""; printer.PushAttribute("line", _callStack.back().line);
} }
xml << " id=\"" << _id << "\""; printer.PushAttribute("id", _id.c_str());
xml << " severity=\"" << (_severity == Severity::error ? "error" : "style") << "\""; printer.PushAttribute("severity", (_severity == Severity::error ? "error" : "style"));
xml << " msg=\"" << stringToXml(verbose ? _verboseMessage : _shortMessage) << "\""; printer.PushAttribute("msg", (verbose ? _verboseMessage : _shortMessage).c_str());
xml << "/>"; printer.CloseElement();
return printer.CStr();
} }
// The xml format you get when you use --xml-version=2 // The xml format you get when you use --xml-version=2
else if (version == 2) { else if (version == 2) {
xml << " <error"; tinyxml2::XMLPrinter printer(0, false, 2);
xml << " id=\"" << _id << "\""; printer.OpenElement("error");
xml << " severity=\"" << Severity::toString(_severity) << "\""; printer.PushAttribute("id", _id.c_str());
xml << " msg=\"" << stringToXml(_shortMessage) << "\""; printer.PushAttribute("severity", Severity::toString(_severity).c_str());
xml << " verbose=\"" << stringToXml(_verboseMessage) << "\""; printer.PushAttribute("msg", _shortMessage.c_str());
printer.PushAttribute("verbose", _verboseMessage.c_str());
if (_inconclusive) if (_inconclusive)
xml << " inconclusive=\"true\""; printer.PushAttribute("inconclusive", "true");
xml << ">" << std::endl;
for (std::list<FileLocation>::const_reverse_iterator it = _callStack.rbegin(); it != _callStack.rend(); ++it) { for (std::list<FileLocation>::const_reverse_iterator it = _callStack.rbegin(); it != _callStack.rend(); ++it) {
xml << " <location"; printer.OpenElement("location");
xml << " file=\"" << stringToXml((*it).getfile()) << "\""; printer.PushAttribute("file", (*it).getfile().c_str());
xml << " line=\"" << (*it).line << "\""; printer.PushAttribute("line", (*it).line);
xml << "/>" << std::endl; printer.CloseElement();
} }
printer.CloseElement();
xml << " </error>"; return printer.CStr();
} }
return xml.str(); return "";
} }
void ErrorLogger::ErrorMessage::findAndReplace(std::string &source, const std::string &searchFor, const std::string &replaceWith) void ErrorLogger::ErrorMessage::findAndReplace(std::string &source, const std::string &searchFor, const std::string &replaceWith)

View File

@ -187,7 +187,7 @@ private:
ErrorMessage msg(locs, Severity::error, "Programming error.\nVerbose error", "errorId", false); ErrorMessage msg(locs, Severity::error, "Programming error.\nVerbose error", "errorId", false);
ASSERT_EQUALS("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<results>", ErrorLogger::ErrorMessage::getXMLHeader(1)); ASSERT_EQUALS("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<results>", ErrorLogger::ErrorMessage::getXMLHeader(1));
ASSERT_EQUALS("</results>", ErrorLogger::ErrorMessage::getXMLFooter(1)); ASSERT_EQUALS("</results>", ErrorLogger::ErrorMessage::getXMLFooter(1));
ASSERT_EQUALS("<error file=\"foo.cpp\" line=\"5\" id=\"errorId\" severity=\"error\" msg=\"Programming error.\"/>", msg.toXML(false,1)); ASSERT_EQUALS(" <error file=\"foo.cpp\" line=\"5\" id=\"errorId\" severity=\"error\" msg=\"Programming error.\"/>", msg.toXML(false,1));
} }
void ToXmlLocations() const { void ToXmlLocations() const {
@ -203,7 +203,7 @@ private:
ErrorMessage msg(locs, Severity::error, "Programming error.\nVerbose error", "errorId", false); ErrorMessage msg(locs, Severity::error, "Programming error.\nVerbose error", "errorId", false);
ASSERT_EQUALS("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<results>", ErrorLogger::ErrorMessage::getXMLHeader(1)); ASSERT_EQUALS("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<results>", ErrorLogger::ErrorMessage::getXMLHeader(1));
ASSERT_EQUALS("</results>", ErrorLogger::ErrorMessage::getXMLFooter(1)); ASSERT_EQUALS("</results>", ErrorLogger::ErrorMessage::getXMLFooter(1));
ASSERT_EQUALS("<error file=\"bar.cpp\" line=\"8\" id=\"errorId\" severity=\"error\" msg=\"Programming error.\"/>", msg.toXML(false,1)); ASSERT_EQUALS(" <error file=\"bar.cpp\" line=\"8\" id=\"errorId\" severity=\"error\" msg=\"Programming error.\"/>", msg.toXML(false,1));
} }
void ToVerboseXml() const { void ToVerboseXml() const {
@ -215,7 +215,7 @@ private:
ErrorMessage msg(locs, Severity::error, "Programming error.\nVerbose error", "errorId", false); ErrorMessage msg(locs, Severity::error, "Programming error.\nVerbose error", "errorId", false);
ASSERT_EQUALS("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<results>", ErrorLogger::ErrorMessage::getXMLHeader(1)); ASSERT_EQUALS("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<results>", ErrorLogger::ErrorMessage::getXMLHeader(1));
ASSERT_EQUALS("</results>", ErrorLogger::ErrorMessage::getXMLFooter(1)); ASSERT_EQUALS("</results>", ErrorLogger::ErrorMessage::getXMLFooter(1));
ASSERT_EQUALS("<error file=\"foo.cpp\" line=\"5\" id=\"errorId\" severity=\"error\" msg=\"Verbose error\"/>", msg.toXML(true,1)); ASSERT_EQUALS(" <error file=\"foo.cpp\" line=\"5\" id=\"errorId\" severity=\"error\" msg=\"Verbose error\"/>", msg.toXML(true,1));
} }
void ToVerboseXmlLocations() const { void ToVerboseXmlLocations() const {
@ -231,7 +231,7 @@ private:
ErrorMessage msg(locs, Severity::error, "Programming error.\nVerbose error", "errorId", false); ErrorMessage msg(locs, Severity::error, "Programming error.\nVerbose error", "errorId", false);
ASSERT_EQUALS("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<results>", ErrorLogger::ErrorMessage::getXMLHeader(1)); ASSERT_EQUALS("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<results>", ErrorLogger::ErrorMessage::getXMLHeader(1));
ASSERT_EQUALS("</results>", ErrorLogger::ErrorMessage::getXMLFooter(1)); ASSERT_EQUALS("</results>", ErrorLogger::ErrorMessage::getXMLFooter(1));
ASSERT_EQUALS("<error file=\"bar.cpp\" line=\"8\" id=\"errorId\" severity=\"error\" msg=\"Verbose error\"/>", msg.toXML(true,1)); ASSERT_EQUALS(" <error file=\"bar.cpp\" line=\"8\" id=\"errorId\" severity=\"error\" msg=\"Verbose error\"/>", msg.toXML(true,1));
} }
void ToXmlV2() const { void ToXmlV2() const {
@ -242,14 +242,14 @@ private:
locs.push_back(loc); locs.push_back(loc);
ErrorMessage msg(locs, Severity::error, "Programming error.\nVerbose error", "errorId", false); ErrorMessage msg(locs, Severity::error, "Programming error.\nVerbose error", "errorId", false);
std::string header("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<results version=\"2\">\n"); std::string header("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<results version=\"2\">\n");
header += " <cppcheck version=\""; header += " <cppcheck version=\"";
header += CppCheck::version(); header += CppCheck::version();
header += "\"/>\n <errors>"; header += "\"/>\n <errors>";
ASSERT_EQUALS(header, ErrorLogger::ErrorMessage::getXMLHeader(2)); ASSERT_EQUALS(header, ErrorLogger::ErrorMessage::getXMLHeader(2));
ASSERT_EQUALS(" </errors>\n</results>", ErrorLogger::ErrorMessage::getXMLFooter(2)); ASSERT_EQUALS(" </errors>\n</results>", ErrorLogger::ErrorMessage::getXMLFooter(2));
std::string message(" <error id=\"errorId\" severity=\"error\""); std::string message(" <error id=\"errorId\" severity=\"error\"");
message += " msg=\"Programming error.\" verbose=\"Verbose error\">\n"; message += " msg=\"Programming error.\" verbose=\"Verbose error\">\n";
message += " <location file=\"foo.cpp\" line=\"5\"/>\n </error>"; message += " <location file=\"foo.cpp\" line=\"5\"/>\n </error>";
ASSERT_EQUALS(message, msg.toXML(false, 2)); ASSERT_EQUALS(message, msg.toXML(false, 2));
} }
@ -265,15 +265,15 @@ private:
locs.push_back(loc2); locs.push_back(loc2);
ErrorMessage msg(locs, Severity::error, "Programming error.\nVerbose error", "errorId", false); ErrorMessage msg(locs, Severity::error, "Programming error.\nVerbose error", "errorId", false);
std::string header("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<results version=\"2\">\n"); std::string header("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<results version=\"2\">\n");
header += " <cppcheck version=\""; header += " <cppcheck version=\"";
header += CppCheck::version(); header += CppCheck::version();
header += "\"/>\n <errors>"; header += "\"/>\n <errors>";
ASSERT_EQUALS(header, ErrorLogger::ErrorMessage::getXMLHeader(2)); ASSERT_EQUALS(header, ErrorLogger::ErrorMessage::getXMLHeader(2));
ASSERT_EQUALS(" </errors>\n</results>", ErrorLogger::ErrorMessage::getXMLFooter(2)); ASSERT_EQUALS(" </errors>\n</results>", ErrorLogger::ErrorMessage::getXMLFooter(2));
std::string message(" <error id=\"errorId\" severity=\"error\""); std::string message(" <error id=\"errorId\" severity=\"error\"");
message += " msg=\"Programming error.\" verbose=\"Verbose error\">\n"; message += " msg=\"Programming error.\" verbose=\"Verbose error\">\n";
message += " <location file=\"bar.cpp\" line=\"8\"/>\n"; message += " <location file=\"bar.cpp\" line=\"8\"/>\n";
message += " <location file=\"foo.cpp\" line=\"5\"/>\n </error>"; message += " <location file=\"foo.cpp\" line=\"5\"/>\n </error>";
ASSERT_EQUALS(message, msg.toXML(false, 2)); ASSERT_EQUALS(message, msg.toXML(false, 2));
} }
@ -292,9 +292,9 @@ private:
ASSERT_EQUALS("", msg.toXML(false, 1)); ASSERT_EQUALS("", msg.toXML(false, 1));
// xml version 2 error message // xml version 2 error message
ASSERT_EQUALS(" <error id=\"errorId\" severity=\"error\" msg=\"Programming error\" verbose=\"Programming error\" inconclusive=\"true\">\n" ASSERT_EQUALS(" <error id=\"errorId\" severity=\"error\" msg=\"Programming error\" verbose=\"Programming error\" inconclusive=\"true\">\n"
" <location file=\"foo.cpp\" line=\"5\"/>\n" " <location file=\"foo.cpp\" line=\"5\"/>\n"
" </error>", " </error>",
msg.toXML(false, 2)); msg.toXML(false, 2));
} }