diff --git a/doc/glmark2.1.in b/doc/glmark2.1.in
index cd8399e0..9dcfb8a6 100644
--- a/doc/glmark2.1.in
+++ b/doc/glmark2.1.in
@@ -55,7 +55,7 @@ Run in fullscreen mode (equivalent to --size -1x-1)
The types of results to report for each benchmark, as a ':' separated list [fps,cpu,shader]
.TP
\fB\-\-results-file\fR RESULTS-FILE
-The file to save the results to, in the format determined by the file extension [csv]
+The file to save the results to, in the format determined by the file extension [csv,xml]
.TP
\fB\-\-winsys-options\fR OPTS
A list of 'opt=value' pairs for window system specific options, separated by ':'
diff --git a/src/options.cpp b/src/options.cpp
index f01aa708..8d1ec16e 100644
--- a/src/options.cpp
+++ b/src/options.cpp
@@ -223,7 +223,7 @@ Options::print_help()
" --results RESULTS The types of results to report for each benchmark,\n"
" as a ':' separated list [fps,cpu,shader]\n"
" --results-file F The file to save the results to, in the format determined\n"
- " by the file extension [csv]\n"
+ " by the file extension [csv,xml]\n"
" --winsys-options O A list of 'opt=value' pairs for window system specific\n"
" options, separated by ':'\n"
" -l, --list-scenes Display information about the available scenes\n"
diff --git a/src/results-file.cpp b/src/results-file.cpp
index f0777619..5762ab72 100644
--- a/src/results-file.cpp
+++ b/src/results-file.cpp
@@ -104,6 +104,72 @@ class CSVResultsFile : public ResultsFile
bool first_field = true;
};
+std::string xml_text_escape(const std::string &str)
+{
+ std::stringstream ss;
+
+ for (auto c : str)
+ {
+ switch (c)
+ {
+ case '<': ss << "<"; break;
+ case '>': ss << ">"; break;
+ case '&': ss << "&"; break;
+ default: ss << c; break;
+ }
+ }
+
+ return ss.str();
+}
+
+class XMLResultsFile : public ResultsFile
+{
+public:
+ XMLResultsFile(std::ofstream &&fs) : fs{std::move(fs)} {}
+
+ std::string type() override { return "XML"; }
+
+ void begin() override
+ {
+ fs << "" << std::endl;
+ fs << "" << std::endl;
+ }
+
+ void end() override
+ {
+ fs << "" << std::endl;
+ }
+
+ void begin_info() override
+ {
+ fs << " " << std::endl;
+ }
+
+ void end_info() override
+ {
+ fs << " " << std::endl;
+ }
+
+ void begin_benchmark() override
+ {
+ fs << " " << std::endl;
+ }
+
+ void end_benchmark() override
+ {
+ fs << " " << std::endl;
+ }
+
+ void add_field(const std::string &name, const std::string &value) override
+ {
+ std::string escaped = xml_text_escape(value);
+ fs << " <" << name << ">" << escaped << "" << name << ">" << std::endl;
+ }
+
+private:
+ std::ofstream fs;
+};
+
std::string get_file_extension(const std::string &str)
{
auto i = str.rfind('.');
@@ -144,6 +210,10 @@ bool ResultsFile::init(const std::string &file)
{
ResultsFile::singleton = std::make_unique(std::move(fs));
}
+ else if (ext == ".xml")
+ {
+ ResultsFile::singleton = std::make_unique(std::move(fs));
+ }
else
{
Log::error("Results file type %s is not supported\n", file.c_str());