[SATYR PATCHv3 2/7] Helper functions for json deserialization

Martin Milata mmilata at redhat.com
Mon Aug 26 14:47:42 UTC 2013


Written in a way to repeat as little code as possible when used:
- when a key is not present in an JSON object, just silently go on,
  validation of required items will be done separately.
- the functions set error_message variable to the description of the
  error when they fail; macros are provided that pass the error_message
  argument implicitly

Signed-off-by: Martin Milata <mmilata at redhat.com>
---
 lib/internal_utils.h | 61 ++++++++++++++++++++++++++++++++++++++++++++++++
 lib/json.c           | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 126 insertions(+)

diff --git a/lib/internal_utils.h b/lib/internal_utils.h
index e69fb97..132905a 100644
--- a/lib/internal_utils.h
+++ b/lib/internal_utils.h
@@ -23,6 +23,11 @@
 #include "utils.h"
 #include <stddef.h>
 #include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+struct sr_json_value;
+enum sr_json_type;
 
 void
 warn(const char *fmt, ...) __sr_printf(1, 2);
@@ -60,4 +65,60 @@ struct sr_taint_flag
 };
 extern struct sr_taint_flag sr_flags[];
 
+/* Checks whether json value is of the right type and sets the error_message if
+ * not. The "name" argument is used in the error message. */
+bool
+json_check_type(struct sr_json_value *value, enum sr_json_type type,
+                const char *name, char **error_message);
+
+/* same as above with implicit error_message argument */
+#define JSON_CHECK_TYPE(value, type, name) json_check_type(value, type, name, error_message)
+
+struct sr_json_value *
+json_element(struct sr_json_value *object, const char *name);
+
+/* These functions check whether JSON object "object" has key "key_name". If it
+ * does not, they don't do anything and return true.
+ *
+ * If it does, they check whether the JSON type of the element corresponds to
+ * the C type of "dest" -- if it does not, they set the error message and
+ * return false.
+ *
+ * Finally, if the type is correct, they write the value to "dest" and return true.
+ */
+bool
+json_read_uint64(struct sr_json_value *object, const char *key_name, uint64_t *dest,
+                 char **error_message);
+bool
+json_read_uint32(struct sr_json_value *object, const char *key_name, uint32_t *dest,
+                 char **error_message);
+bool
+json_read_uint16(struct sr_json_value *object, const char *key_name, uint16_t *dest,
+                 char **error_message);
+bool
+json_read_string(struct sr_json_value *object, const char *key_name, char **dest,
+                 char **error_message);
+bool
+json_read_bool(struct sr_json_value *object, const char *key_name, bool *dest,
+               char **error_message);
+
+/* same as above with implicit error_message argument */
+#define JSON_READ_UINT64(object, key_name, dest) \
+    json_read_uint64(object, key_name, dest, error_message)
+#define JSON_READ_UINT32(object, key_name, dest) \
+    json_read_uint32(object, key_name, dest, error_message)
+#define JSON_READ_UINT16(object, key_name, dest) \
+    json_read_uint16(object, key_name, dest, error_message)
+#define JSON_READ_STRING(object, key_name, dest) \
+    json_read_string(object, key_name, dest, error_message)
+#define JSON_READ_BOOL(object, key_name, dest) \
+    json_read_bool(object, key_name, dest, error_message)
+
+/* iterates over json array "json", assigning the current element to "elem_var" */
+#define FOR_JSON_ARRAY(json, elem_var)                                      \
+    assert(json->type == SR_JSON_ARRAY);                                    \
+    for(unsigned _j = 0;                                                    \
+        _j < json->u.array.length && (elem_var = json->u.array.values[_j]); \
+        ++_j)
+
 #endif
diff --git a/lib/json.c b/lib/json.c
index 1e6ab79..aa60c0a 100644
--- a/lib/json.c
+++ b/lib/json.c
@@ -37,6 +37,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <ctype.h>
+#include <assert.h>
 
 typedef unsigned short json_uchar;
 
@@ -740,3 +741,67 @@ sr_json_append_escaped(struct sr_strbuf *strbuf, const char *str)
 
     return strbuf;
 }
+
+static char *type_names[] = {
+   [SR_JSON_NONE]    = "none",
+   [SR_JSON_OBJECT]  = "object",
+   [SR_JSON_ARRAY]   = "array",
+   [SR_JSON_INTEGER] = "integer",
+   [SR_JSON_DOUBLE]  = "double",
+   [SR_JSON_STRING]  = "string",
+   [SR_JSON_BOOLEAN] = "boolean",
+   [SR_JSON_NULL]    = "null",
+};
+bool
+json_check_type(struct sr_json_value *value, enum sr_json_type type,
+                const char *name, char **error_message)
+{
+    if (value->type == type)
+        return true;
+
+    assert(type >= SR_JSON_NONE && type <= SR_JSON_NULL);
+    char *type_str = type_names[type];
+
+    if (error_message)
+        *error_message = sr_asprintf("Invalid type of %s; %s expected", name, type_str);
+    return false;
+}
+
+struct sr_json_value *
+json_element(struct sr_json_value *object, const char *key_name)
+{
+    assert(object->type == SR_JSON_OBJECT);
+
+    for (unsigned i = 0; i < object->u.object.length; ++i)
+    {
+        if (0 == strcmp(key_name, object->u.object.values[i].name))
+            return object->u.object.values[i].value;
+    }
+
+    return NULL;
+}
+
+#define DEFINE_JSON_READ(name, c_type, json_type, json_member, conversion)                       \
+    bool                                                                                         \
+    name(struct sr_json_value *object, const char *key_name, c_type *dest, char **error_message) \
+    {                                                                                            \
+        struct sr_json_value *val = json_element(object, key_name);                              \
+                                                                                                 \
+        if (!val)                                                                                \
+            return true;                                                                         \
+                                                                                                 \
+        if (!json_check_type(val, json_type, key_name, error_message))                           \
+            return false;                                                                        \
+                                                                                                 \
+        *dest = conversion(val->json_member);                                                    \
+                                                                                                 \
+        return true;                                                                             \
+    }
+
+#define NOOP
+
+DEFINE_JSON_READ(json_read_uint64, uint64_t, SR_JSON_INTEGER, u.integer, NOOP)
+DEFINE_JSON_READ(json_read_uint32, uint32_t, SR_JSON_INTEGER, u.integer, NOOP)
+DEFINE_JSON_READ(json_read_uint16, uint16_t, SR_JSON_INTEGER, u.integer, NOOP)
+DEFINE_JSON_READ(json_read_string, char *, SR_JSON_STRING, u.string.ptr, sr_strdup)
+DEFINE_JSON_READ(json_read_bool, bool, SR_JSON_BOOLEAN, u.boolean, NOOP)
-- 
1.8.3.1



More information about the Crash-catcher mailing list