[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