++entry.size;
}
-void JSONFormatter::open_section(const char *name, bool is_array)
+void JSONFormatter::open_section(const char *name, const char *ns, bool is_array)
{
- print_name(name);
+ if (handle_open_section(name, ns, is_array)) {
+ return;
+ }
+ if (ns) {
+ std::ostringstream oss;
+ oss << name << " " << ns;
+ print_name(oss.str().c_str());
+ } else {
+ print_name(name);
+ }
if (is_array)
m_ss << '[';
else
void JSONFormatter::open_array_section(const char *name)
{
- open_section(name, true);
+ open_section(name, nullptr, true);
}
void JSONFormatter::open_array_section_in_ns(const char *name, const char *ns)
{
- std::ostringstream oss;
- oss << name << " " << ns;
- open_section(oss.str().c_str(), true);
+ open_section(name, ns, true);
}
void JSONFormatter::open_object_section(const char *name)
{
- open_section(name, false);
+ open_section(name, nullptr, false);
}
void JSONFormatter::open_object_section_in_ns(const char *name, const char *ns)
{
- std::ostringstream oss;
- oss << name << " " << ns;
- open_section(oss.str().c_str(), false);
+ open_section(name, ns, false);
}
void JSONFormatter::close_section()
{
+
+ if (handle_close_section()) {
+ return;
+ }
ceph_assert(!m_stack.empty());
finish_pending_string();
void JSONFormatter::finish_pending_string()
{
if (m_is_pending_string) {
- print_quoted_string(m_pending_string.str());
- m_pending_string.str(std::string());
m_is_pending_string = false;
+ add_value(m_pending_name.c_str(), m_pending_string.str(), true);
}
}
-void JSONFormatter::dump_unsigned(const char *name, uint64_t u)
+template <class T>
+void JSONFormatter::add_value(const char *name, T val)
+{
+ std::stringstream ss;
+ ss << val;
+ add_value(name, ss.str(), false);
+}
+
+void JSONFormatter::add_value(const char *name, std::string_view val, bool quoted)
{
+ if (handle_value(name, val, quoted)) {
+ return;
+ }
print_name(name);
- m_ss << u;
+ if (!quoted) {
+ m_ss << val;
+ } else {
+ print_quoted_string(val);
+ }
+}
+
+void JSONFormatter::dump_unsigned(const char *name, uint64_t u)
+{
+ add_value(name, u);
}
void JSONFormatter::dump_int(const char *name, int64_t s)
{
- print_name(name);
- m_ss << s;
+ add_value(name, s);
}
void JSONFormatter::dump_float(const char *name, double d)
{
- print_name(name);
char foo[30];
snprintf(foo, sizeof(foo), "%lf", d);
- m_ss << foo;
+ add_value(name, foo, false);
}
void JSONFormatter::dump_string(const char *name, std::string_view s)
{
- print_name(name);
- print_quoted_string(s);
+ add_value(name, s, true);
}
std::ostream& JSONFormatter::dump_stream(const char *name)
{
- print_name(name);
+ m_pending_name = name;
m_is_pending_string = true;
return m_pending_string;
}
char buf[LARGE_SIZE];
vsnprintf(buf, LARGE_SIZE, fmt, ap);
- print_name(name);
- if (quoted) {
- print_quoted_string(std::string(buf));
- } else {
- m_ss << std::string(buf);
- }
+ add_value(name, buf, quoted);
}
int JSONFormatter::get_len() const
}
};
+ class copyable_sstream : public std::stringstream {
+ public:
+ copyable_sstream() {}
+ copyable_sstream(const copyable_sstream& rhs) {
+ str(rhs.str());
+ }
+ copyable_sstream& operator=(const copyable_sstream& rhs) {
+ str(rhs.str());
+ return *this;
+ }
+ };
+
class JSONFormatter : public Formatter {
public:
explicit JSONFormatter(bool p = false);
int get_len() const override;
void write_raw_data(const char *data) override;
+ protected:
+ virtual bool handle_value(const char *name, std::string_view s, bool quoted) {
+ return false; /* is handling done? */
+ }
+
+ virtual bool handle_open_section(const char *name, const char *ns, bool is_array) {
+ return false; /* is handling done? */
+ }
+
+ virtual bool handle_close_section() {
+ return false; /* is handling done? */
+ }
+
private:
struct json_formatter_stack_entry_d {
};
bool m_pretty;
- void open_section(const char *name, bool is_array);
+ void open_section(const char *name, const char *ns, bool is_array);
void print_quoted_string(std::string_view s);
void print_name(const char *name);
void print_comma(json_formatter_stack_entry_d& entry);
void finish_pending_string();
- std::stringstream m_ss, m_pending_string;
+ template <class T>
+ void add_value(const char *name, T val);
+ void add_value(const char *name, std::string_view val, bool quoted);
+
+ copyable_sstream m_ss;
+ copyable_sstream m_pending_string;
+ std::string m_pending_name;
std::list<json_formatter_stack_entry_d> m_stack;
bool m_is_pending_string;
bool m_line_break_enabled = false;
};
+ template <class T>
+ void add_value(const char *name, T val);
+
class XMLFormatter : public Formatter {
public:
static const char *XML_1_DTD;
std::vector< std::string > m_column_name;
};
-
}
#endif
#include <boost/algorithm/string.hpp>
#include <boost/tokenizer.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include "json_spirit/json_spirit_writer_template.h"
using namespace json_spirit;
static JSONFormattable default_formattable;
+void encode_json(const char *name, const JSONObj::data_val& v, Formatter *f)
+{
+ if (v.quoted) {
+ encode_json(name, v.str, f);
+ } else {
+ f->dump_format_unquoted(name, "%s", v.str.c_str());
+ }
+}
+
JSONObjIter::JSONObjIter()
{
}
// does not work, FIXME
ostream& operator<<(ostream &out, const JSONObj &obj) {
- out << obj.name << ": " << obj.data_string;
+ out << obj.name << ": " << obj.val;
return out;
}
children.insert(pair<string, JSONObj *>(el, obj));
}
-bool JSONObj::get_attr(string name, string& attr)
+bool JSONObj::get_attr(string name, data_val& attr)
{
- map<string, string>::iterator iter = attr_map.find(name);
+ auto iter = attr_map.find(name);
if (iter == attr_map.end())
return false;
attr = iter->second;
return *iter;
}
-bool JSONObj::get_data(const string& key, string *dest)
+bool JSONObj::get_data(const string& key, data_val *dest)
{
JSONObj *obj = find_obj(key);
if (!obj)
return false;
- *dest = obj->get_data();
+ *dest = obj->get_data_val();
return true;
}
data = v;
handle_value(v);
- if (v.type() == str_type)
- data_string = v.get_str();
- else
- data_string = write(v, raw_utf8);
- attr_map.insert(pair<string,string>(name, data_string));
+ if (v.type() != obj_type &&
+ v.type() != array_type) {
+ if (v.type() == str_type) {
+ val.set(v.get_str(), true);
+ } else {
+ val.set(json_spirit::write_string(v), false);
+ }
+ }
+ attr_map.insert(pair<string,data_val>(name, val));
}
JSONObj *JSONObj::get_parent()
handle_value(data);
if (data.type() != obj_type &&
data.type() != array_type) {
- if (data.type() == str_type)
- data_string = data.get_str();
- else
- data_string = write(data, raw_utf8);
+ if (data.type() == str_type) {
+ val.set(data.get_str(), true);
+ } else {
+ val.set(json_spirit::write_string(data), false);
+ }
}
} else {
set_failure();
}
int JSONFormattable::val_int() const {
- return atoi(str.c_str());
+ return atoi(value.str.c_str());
}
bool JSONFormattable::val_bool() const {
- return (boost::iequals(str, "true") ||
- boost::iequals(str, "on") ||
- boost::iequals(str, "yes") ||
- boost::iequals(str, "1"));
+ return (boost::iequals(value.str, "true") ||
+ boost::iequals(value.str, "on") ||
+ boost::iequals(value.str, "yes") ||
+ boost::iequals(value.str, "1"));
}
string JSONFormattable::def(const string& def_val) const {
return 0;
}
+static bool is_numeric(const string& val)
+{
+ try {
+ boost::lexical_cast<double>(val);
+ } catch (const boost::bad_lexical_cast& e) {
+ return false;
+ }
+ return true;
+}
+
int JSONFormattable::set(const string& name, const string& val)
{
boost::escaped_list_separator<char> els('\\', '.', '"');
if (is_valid_json) {
f->decode_json(&jp);
} else {
- f->type = FMT_STRING;
- f->str = val;
+ f->type = FMT_VALUE;
+ f->value.set(val, !is_numeric(val));
}
return 0;
}
for (const auto& vi : v) {
if (f->type == FMT_NONE ||
- f->type == FMT_STRING) {
+ f->type == FMT_VALUE) {
if (vi.is_obj) {
f->type = FMT_OBJ;
} else {
void encode_json(const char *name, const JSONFormattable& v, Formatter *f)
{
- switch (v.type) {
- case JSONFormattable::FMT_STRING:
- encode_json(name, v.str, f);
+ v.encode_json(name, f);
+}
+
+void JSONFormattable::encode_json(const char *name, Formatter *f) const
+{
+ switch (type) {
+ case JSONFormattable::FMT_VALUE:
+ ::encode_json(name, value, f);
break;
case JSONFormattable::FMT_ARRAY:
- encode_json(name, v.arr, f);
+ ::encode_json(name, arr, f);
break;
case JSONFormattable::FMT_OBJ:
f->open_object_section(name);
- for (auto iter : v.obj) {
- encode_json(iter.first.c_str(), iter.second, f);
+ for (auto iter : obj) {
+ ::encode_json(iter.first.c_str(), iter.second, f);
}
f->close_section();
break;
class JSONObj
{
JSONObj *parent;
+public:
+ struct data_val {
+ string str;
+ bool quoted{false};
+
+ void set(std::string_view s, bool q) {
+ str = s;
+ quoted = q;
+ }
+ };
protected:
string name; // corresponds to obj_type in XMLObj
Value data;
- string data_string;
+ struct data_val val;
+ bool data_quoted{false};
multimap<string, JSONObj *> children;
- map<string, string> attr_map;
+ map<string, data_val> attr_map;
void handle_value(Value v);
public:
void init(JSONObj *p, Value v, string n);
string& get_name() { return name; }
- string& get_data() { return data_string; }
- bool get_data(const string& key, string *dest);
+ data_val& get_data_val() { return val; }
+ const string& get_data() { return val.str; }
+ bool get_data(const string& key, data_val *dest);
JSONObj *get_parent();
void add_child(string el, JSONObj *child);
- bool get_attr(string name, string& attr);
+ bool get_attr(string name, data_val& attr);
JSONObjIter find(const string& name);
JSONObjIter find_first();
JSONObjIter find_first(const string& name);
vector<string> get_array_elements();
};
+static inline ostream& operator<<(ostream &out, const JSONObj::data_val& dv) {
+ const char *q = (dv.quoted ? "\"" : "");
+ out << q << dv.str << q;
+ return out;
+}
+
class JSONParser : public JSONObj
{
int buf_len;
void set_failure() { success = false; }
};
+void encode_json(const char *name, const JSONObj::data_val& v, Formatter *f);
class JSONDecoder {
public:
val = obj->get_data();
}
+static inline void decode_json_obj(JSONObj::data_val& val, JSONObj *obj)
+{
+ val = obj->get_data_val();
+}
+
void decode_json_obj(unsigned long long& val, JSONObj *obj);
void decode_json_obj(long long& val, JSONObj *obj);
void decode_json_obj(unsigned long& val, JSONObj *obj);
encode_json_map<K, V>(name, index_name, NULL, value_name, NULL, NULL, m, f);
}
-struct JSONFormattable {
+class JSONFormattable : public ceph::JSONFormatter {
+ JSONObj::data_val value;
+ vector<JSONFormattable> arr;
+ map<std::string, JSONFormattable> obj;
+
+ vector<JSONFormattable *> enc_stack;
+ JSONFormattable *cur_enc;
+
+protected:
+ bool handle_value(const char *name, std::string_view s, bool quoted) override {
+ JSONFormattable *new_val;
+ if (cur_enc->is_array()) {
+ cur_enc->arr.push_back(JSONFormattable());
+ new_val = &cur_enc->arr.back();
+ } else {
+ new_val = &cur_enc->obj[name];
+ }
+ new_val->set_type(JSONFormattable::FMT_VALUE);
+ new_val->value.set(s, quoted);
+
+ return false;
+ }
+ bool handle_open_section(const char *name, const char *ns, bool section_is_array) override {
+ if (cur_enc->is_array()) {
+ cur_enc->arr.push_back(JSONFormattable());
+ cur_enc = &cur_enc->arr.back();
+ } else {
+ cur_enc = &obj[name];
+ }
+ enc_stack.push_back(cur_enc);
+
+ if (section_is_array) {
+ cur_enc->set_type(JSONFormattable::FMT_ARRAY);
+ } else {
+ cur_enc->set_type(JSONFormattable::FMT_OBJ);
+ }
+
+ return false; /* continue processing */
+ }
+ bool handle_close_section() override {
+ if (enc_stack.size() <= 1) {
+ return false;
+ }
+
+ enc_stack.pop_back();
+ cur_enc = enc_stack.back();
+ return false; /* continue processing */
+ }
+
+public:
+ JSONFormattable(bool p = false) : JSONFormatter(p) {
+ cur_enc = this;
+ enc_stack.push_back(cur_enc);
+ }
+
enum Type {
FMT_NONE,
- FMT_STRING,
+ FMT_VALUE,
FMT_ARRAY,
FMT_OBJ,
} type{FMT_NONE};
- string str;
- vector<JSONFormattable> arr;
- map<std::string, JSONFormattable> obj;
+ void set_type(Type t) {
+ type = t;
+ }
+
void decode_json(JSONObj *jo) {
if (jo->is_array()) {
- type = JSONFormattable::FMT_ARRAY;
+ set_type(JSONFormattable::FMT_ARRAY);
decode_json_obj(arr, jo);
} else if (jo->is_object()) {
- type = JSONFormattable::FMT_OBJ;
+ set_type(JSONFormattable::FMT_OBJ);
auto iter = jo->find_first();
for (;!iter.end(); ++iter) {
JSONObj *field = *iter;
decode_json_obj(obj[field->get_name()], field);
}
} else {
- type = JSONFormattable::FMT_STRING;
- decode_json_obj(str, jo);
+ set_type(JSONFormattable::FMT_VALUE);
+ decode_json_obj(value, jo);
}
}
void encode(bufferlist& bl) const {
- ENCODE_START(1, 1, bl);
+ ENCODE_START(2, 1, bl);
encode((uint8_t)type, bl);
- encode(str, bl);
+ encode(value.str, bl);
encode(arr, bl);
encode(obj, bl);
+ encode(value.quoted, bl);
ENCODE_FINISH(bl);
}
void decode(bufferlist::const_iterator& bl) {
- DECODE_START(1, bl);
+ DECODE_START(2, bl);
uint8_t t;
decode(t, bl);
type = (Type)t;
- decode(str, bl);
+ decode(value.str, bl);
decode(arr, bl);
decode(obj, bl);
+ if (struct_v >= 2) {
+ decode(value.quoted, bl);
+ } else {
+ value.quoted = true;
+ }
DECODE_FINISH(bl);
}
const std::string& val() const {
- return str;
+ return value.str;
}
int val_int() const;
JSONFormattable& operator[](size_t index);
operator std::string() const {
- return str;
+ return value.str;
}
explicit operator int() const {
return def(string(def_val));
}
-#if 0
- string operator ()(const string& def_val) const {
- return def(def_val);
- }
-#endif
-
int operator()(int def_val) const {
return def(def_val);
}
int erase(const string& name);
void derive_from(const JSONFormattable& jf);
+
+ void encode_json(const char *name, Formatter *f) const;
+
+ bool is_array() const {
+ return (type == FMT_ARRAY);
+ }
};
WRITE_CLASS_ENCODER(JSONFormattable)
{
JSONParser p;
bool result = p.parse(s.c_str(), s.size());
+ if (!result) {
+ cout << "Failed to parse: '" << s << "'" << std::endl;
+ }
ASSERT_EQ(true, result);
try {
decode_json_obj(*f, &p);