summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYehuda Sadeh <yehuda@inktank.com>2013-02-06 12:36:18 -0800
committerYehuda Sadeh <yehuda@inktank.com>2013-02-11 17:05:06 -0800
commitbfb35d3275803c1e22f740d5b2687de2cf617044 (patch)
tree402771ef19ab805605ddb1bb2114ea9c48389abc
parent70532d198539f94067e53ef48dd7d1f5114fa27d (diff)
downloadceph-bfb35d3275803c1e22f740d5b2687de2cf617044.tar.gz
rgw: introduce decode_json to easily decode json structures
Introducing a new way to define the json structure of an object, similar to what we do with bufferlist encode/decode. Signed-off-by: Yehuda Sadeh <yehuda@inktank.com>
-rw-r--r--src/rgw/rgw_json.cc97
-rw-r--r--src/rgw/rgw_json.h100
2 files changed, 193 insertions, 4 deletions
diff --git a/src/rgw/rgw_json.cc b/src/rgw/rgw_json.cc
index 0f91c2279e1..3cff30aa37b 100644
--- a/src/rgw/rgw_json.cc
+++ b/src/rgw/rgw_json.cc
@@ -268,4 +268,101 @@ bool RGWJSONParser::parse(const char *file_name)
}
+void decode_json_obj(long& val, JSONObj *obj)
+{
+ string s = obj->get_data();
+ const char *start = s.c_str();
+ char *p;
+
+ errno = 0;
+ val = strtol(start, &p, 10);
+
+ /* Check for various possible errors */
+
+ if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) ||
+ (errno != 0 && val == 0)) {
+ throw JSONDecoder::err("failed to parse number");
+ }
+
+ if (p == start) {
+ throw JSONDecoder::err("failed to parse number");
+ }
+
+ while (*p != '\0') {
+ if (!isspace(*p)) {
+ throw JSONDecoder::err("failed to parse number");
+ }
+ p++;
+ }
+}
+
+void decode_json_obj(unsigned long& val, JSONObj *obj)
+{
+ string s = obj->get_data();
+ const char *start = s.c_str();
+ char *p;
+
+ errno = 0;
+ val = strtoul(start, &p, 10);
+
+ /* Check for various possible errors */
+
+ if ((errno == ERANGE && val == ULONG_MAX) ||
+ (errno != 0 && val == 0)) {
+ throw JSONDecoder::err("failed to number");
+ }
+
+ if (p == start) {
+ throw JSONDecoder::err("failed to parse number");
+ }
+
+ while (*p != '\0') {
+ if (!isspace(*p)) {
+ throw JSONDecoder::err("failed to parse number");
+ }
+ p++;
+ }
+}
+
+void decode_json_obj(int& val, JSONObj *obj)
+{
+ long l;
+ decode_json_obj(l, obj);
+#if LONG_MAX > INT_MAX
+ if (l > INT_MAX || l < INT_MIN) {
+ throw JSONDecoder::err("integer out of range");
+ }
+#endif
+
+ val = (int)l;
+}
+
+void decode_json_obj(unsigned& val, JSONObj *obj)
+{
+ unsigned long l;
+ decode_json_obj(l, obj);
+#if ULONG_MAX > UINT_MAX
+ if (l > UINT_MAX) {
+ throw JSONDecoder::err("unsigned integer out of range");
+ }
+#endif
+
+ val = (unsigned)l;
+}
+
+void decode_json_obj(bool& val, JSONObj *obj)
+{
+ string s = obj->get_data();
+ if (strcasecmp(s.c_str(), "true") == 0) {
+ val = true;
+ return;
+ }
+ if (strcasecmp(s.c_str(), "false") == 0) {
+ val = true;
+ return;
+ }
+ int i;
+ decode_json_obj(i, obj);
+ val = (bool)i;
+}
diff --git a/src/rgw/rgw_json.h b/src/rgw/rgw_json.h
index d0dec397c28..4b6f00d9286 100644
--- a/src/rgw/rgw_json.h
+++ b/src/rgw/rgw_json.h
@@ -4,13 +4,9 @@
#include <iostream>
#include <include/types.h>
-// for testing DELETE ME
-#include <fstream>
-
#include "json_spirit/json_spirit.h"
-using namespace std;
using namespace json_spirit;
@@ -91,4 +87,100 @@ public:
};
+class JSONDecoder {
+public:
+ struct err {
+ string message;
+
+ err(const string& m) : message(m) {}
+ };
+
+ RGWJSONParser parser;
+
+ JSONDecoder(bufferlist& bl) {
+ if (!parser.parse(bl.c_str(), bl.length())) {
+ cout << "JSONDecoder::err()" << std::endl;
+ throw JSONDecoder::err("failed to parse JSON input");
+ }
+ }
+
+ template<class T>
+ static bool decode_json(const string& name, T& val, JSONObj *obj, bool mandatory = false);
+
+ template<class T>
+ static void decode_json(const string& name, T& val, T& default_val, JSONObj *obj);
+};
+
+template<class T>
+void decode_json_obj(T& val, JSONObj *obj)
+{
+ val.decode_json(obj);
+}
+
+static inline void decode_json_obj(string& val, JSONObj *obj)
+{
+ val = obj->get_data();
+}
+
+void decode_json_obj(unsigned long& val, JSONObj *obj);
+void decode_json_obj(long& val, JSONObj *obj);
+void decode_json_obj(unsigned& val, JSONObj *obj);
+void decode_json_obj(int& val, JSONObj *obj);
+void decode_json_obj(bool& val, JSONObj *obj);
+
+template<class T>
+void decode_json_obj(list<T>& l, JSONObj *obj)
+{
+ JSONObjIter iter = obj->find_first();
+
+ for (; !iter.end(); ++iter) {
+ T val;
+ JSONObj *o = *iter;
+ decode_json_obj(val, o);
+ l.push_back(val);
+ }
+}
+
+template<class T>
+bool JSONDecoder::decode_json(const string& name, T& val, JSONObj *obj, bool mandatory)
+{
+ JSONObjIter iter = obj->find_first(name);
+ if (iter.end()) {
+ if (mandatory) {
+ string s = "missing mandatory field " + name;
+ throw err(s);
+ }
+ return false;
+ }
+
+ try {
+ decode_json_obj(val, *iter);
+ } catch (err& e) {
+ string s = name + ": ";
+ s.append(e.message);
+ throw err(s);
+ }
+
+ return true;
+}
+
+template<class T>
+void JSONDecoder::decode_json(const string& name, T& val, T& default_val, JSONObj *obj)
+{
+ JSONObjIter iter = obj->find_first(name);
+ if (iter.end()) {
+ val = default_val;
+ return;
+ }
+
+ try {
+ decode_json_obj(val, *iter);
+ } catch (err& e) {
+ val = default_val;
+ string s = name + ": ";
+ s.append(e.message);
+ throw err(s);
+ }
+}
+
#endif