#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
+#include <vector>
// -----------------------
namespace ceph {
print_quoted_string(buf);
}
+XMLFormatter::
+XMLFormatter(bool p)
+ : m_pretty(p)
+{
+}
+
+void XMLFormatter::
+flush(std::ostream& os)
+{
+ finish_pending_string();
+ assert(m_sections.empty());
+ os << m_ss.str();
+ m_ss.clear();
+}
+
+void XMLFormatter::
+open_array_section(const char *name)
+{
+ open_section(name);
+}
+
+void XMLFormatter::
+open_object_section(const char *name)
+{
+ open_section(name);
+}
+
+void XMLFormatter::
+close_section()
+{
+ assert(!m_sections.empty());
+
+ print_spaces(false);
+ m_ss << "</" << m_sections.back() << ">";
+ m_sections.pop_back();
+}
+
+void XMLFormatter::
+dump_unsigned(const char *name, uint64_t u)
+{
+ std::string e(escape_xml_str(name));
+ print_spaces(true);
+ m_ss << "<" << e << ">" << u << "</" << e << ">";
+ if (m_pretty)
+ m_ss << "\n";
+}
+
+void XMLFormatter::
+dump_int(const char *name, int64_t u)
+{
+ std::string e(escape_xml_str(name));
+ print_spaces(true);
+ m_ss << "<" << e << ">" << u << "</" << e << ">";
+ if (m_pretty)
+ m_ss << "\n";
+}
+
+void XMLFormatter::
+dump_float(const char *name, double d)
+{
+ std::string e(escape_xml_str(name));
+ print_spaces(true);
+ m_ss << "<" << e << ">" << d << "</" << e << ">";
+ if (m_pretty)
+ m_ss << "\n";
+}
+
+void XMLFormatter::
+dump_string(const char *name, std::string s)
+{
+ std::string e(escape_xml_str(name));
+ print_spaces(true);
+ m_ss << "<" << e << ">" << escape_xml_str(s.c_str()) << "</" << e << ">";
+ if (m_pretty)
+ m_ss << "\n";
+}
+
+std::ostream& XMLFormatter::
+dump_stream(const char *name)
+{
+ assert(m_pending_string_name.empty());
+ m_pending_string_name = escape_xml_str(name);
+ m_ss << "<" << m_pending_string_name << ">";
+ return m_pending_string;
+}
+
+void XMLFormatter::
+dump_format(const char *name, const char *fmt, ...)
+{
+ char buf[LARGE_SIZE];
+ va_list ap;
+ va_start(ap, fmt);
+ vsnprintf(buf, LARGE_SIZE, fmt, ap);
+ va_end(ap);
+
+ std::string e(escape_xml_str(name));
+ print_spaces(true);
+ m_ss << "<" << e << ">" << escape_xml_str(buf) << "</" << e << ">";
+ if (m_pretty)
+ m_ss << "\n";
+}
+
+void XMLFormatter::
+open_section(const char *name)
+{
+ print_spaces(false);
+ std::string escaped_name(escape_xml_str(name));
+ m_sections.push_back(escaped_name);
+ m_ss << "<" << escaped_name << ">";
+}
+
+void XMLFormatter::
+finish_pending_string()
+{
+ if (!m_pending_string_name.empty()) {
+ m_ss << escape_xml_str(m_pending_string.str().c_str())
+ << "</" << m_pending_string_name << ">";
+ m_pending_string_name.clear();
+ if (m_pretty) {
+ m_ss << "\n";
+ }
+ }
+}
+
+void XMLFormatter::
+print_spaces(bool extra_space)
+{
+ finish_pending_string();
+ if (m_pretty) {
+ std::vector<char> spaces(m_sections.size(), ' ');
+ if (extra_space)
+ spaces.push_back(' ');
+ spaces.push_back('\0');
+ m_ss << &spaces[0];
+ }
+}
+
+std::string XMLFormatter::
+escape_xml_str(const char *str)
+{
+ int len = escape_xml_attr_len(str);
+ std::vector<char> escaped(len, '\0');
+ escape_xml_attr(str, &escaped[0]);
+ return std::string(&escaped[0]);
+}
+
}
#ifndef CEPH_FORMATTER_H
#define CEPH_FORMATTER_H
+#include <deque>
#include <inttypes.h>
#include <iostream>
#include <list>
bool m_is_pending_string;
};
+class XMLFormatter : public Formatter {
+ public:
+ XMLFormatter(bool p=false);
+
+ void flush(std::ostream& os);
+ void open_array_section(const char *name);
+ void open_object_section(const char *name);
+ void close_section();
+ void dump_unsigned(const char *name, uint64_t u);
+ void dump_int(const char *name, int64_t u);
+ void dump_float(const char *name, double d);
+ void dump_string(const char *name, std::string s);
+ std::ostream& dump_stream(const char *name);
+ void dump_format(const char *name, const char *fmt, ...);
+
+ private:
+ void open_section(const char *name);
+ void finish_pending_string();
+ void print_spaces(bool extra_space);
+ static std::string escape_xml_str(const char *str);
+
+ std::stringstream m_ss, m_pending_string;
+ std::deque<std::string> m_sections;
+ bool m_pretty;
+ std::string m_pending_string_name;
+};
+
}
#endif
fmt.flush(oss);
ASSERT_EQ(oss.str(), "");
}
+
+TEST(XmlFormatter, Simple1) {
+ ostringstream oss;
+ XMLFormatter fmt(false);
+ fmt.open_object_section("foo");
+ fmt.dump_int("a", 1);
+ fmt.dump_int("b", 2);
+ fmt.dump_int("c", 3);
+ fmt.close_section();
+ fmt.flush(oss);
+ ASSERT_EQ(oss.str(), "<foo><a>1</a><b>2</b><c>3</c></foo>");
+}
+
+TEST(XmlFormatter, Simple2) {
+ ostringstream oss;
+ XMLFormatter fmt(false);
+ fmt.open_object_section("foo");
+ fmt.open_object_section("bar");
+ fmt.dump_int("int", 0xf00000000000ll);
+ fmt.dump_unsigned("unsigned", 0x8000000000000001llu);
+ fmt.dump_float("float", 1.234);
+ fmt.close_section();
+ fmt.dump_string("string", "str");
+ fmt.close_section();
+ fmt.flush(oss);
+ ASSERT_EQ(oss.str(), "<foo><bar>\
+<int>263882790666240</int>\
+<unsigned>9223372036854775809</unsigned>\
+<float>1.234</float>\
+</bar><string>str</string>\
+</foo>");
+}
+
+TEST(XmlFormatter, Empty) {
+ ostringstream oss;
+ XMLFormatter fmt(false);
+ fmt.flush(oss);
+ ASSERT_EQ(oss.str(), "");
+}
+
+TEST(XmlFormatter, DumpStream1) {
+ ostringstream oss;
+ XMLFormatter fmt(false);
+ fmt.dump_stream("blah") << "hithere";
+ fmt.flush(oss);
+ ASSERT_EQ(oss.str(), "<blah>hithere</blah>");
+}
+
+TEST(XmlFormatter, DumpStream2) {
+ ostringstream oss;
+ XMLFormatter fmt(false);
+
+ fmt.open_array_section("foo");
+ fmt.dump_stream("blah") << "hithere";
+ fmt.close_section();
+ fmt.flush(oss);
+ ASSERT_EQ(oss.str(), "<foo><blah>hithere</blah></foo>");
+}
+
+TEST(XmlFormatter, DumpStream3) {
+ ostringstream oss;
+ XMLFormatter fmt(false);
+
+ fmt.open_array_section("foo");
+ fmt.dump_stream("blah") << "hithere";
+ fmt.dump_float("pi", 3.14);
+ fmt.close_section();
+ fmt.flush(oss);
+ ASSERT_EQ(oss.str(), "<foo><blah>hithere</blah><pi>3.14</pi></foo>");
+}