]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: introduce decode_json to easily decode json structures
authorYehuda Sadeh <yehuda@inktank.com>
Wed, 6 Feb 2013 20:36:18 +0000 (12:36 -0800)
committerYehuda Sadeh <yehuda@inktank.com>
Fri, 22 Mar 2013 18:23:07 +0000 (11:23 -0700)
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>
src/rgw/rgw_json.cc
src/rgw/rgw_json.h

index 0f91c2279e1f027b96733b7bb4debd73081e443d..3cff30aa37bd8eb82c6746ecae346f7e3290783c 100644 (file)
@@ -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;
+}
 
index d0dec397c28845c449b827f22fc35eb6aef08ed2..4b6f00d92863e33e01f53b58feb31820a634ddba 100644 (file)
@@ -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