[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH V6 2/3] libxl: Introduce JSON parsing stuff.



We use the yajl parser, but we need to make a tree from the parse result
to use it outside the parser.

So this patch include json_object struct that is used to hold the JSON
data.

Signed-off-by: Anthony PERARD <anthony.perard@xxxxxxxxxx>
---
 tools/libxl/Makefile         |    5 +-
 tools/libxl/libxl_internal.h |   97 ++++++++
 tools/libxl/libxl_json.c     |  521 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 622 insertions(+), 1 deletions(-)
 create mode 100644 tools/libxl/libxl_json.c

diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile
index a95cd5d..0306cb0 100644
--- a/tools/libxl/Makefile
+++ b/tools/libxl/Makefile
@@ -32,9 +32,12 @@ endif
 LIBXL_OBJS-$(CONFIG_X86) += libxl_cpuid.o
 LIBXL_OBJS-$(CONFIG_IA64) += libxl_nocpuid.o
 
+LIBXL_LIBS += -lyajl
+
 LIBXL_OBJS = flexarray.o libxl.o libxl_create.o libxl_dm.o libxl_pci.o \
                        libxl_dom.o libxl_exec.o libxl_xshelp.o libxl_device.o \
-                       libxl_internal.o libxl_utils.o libxl_uuid.o 
$(LIBXL_OBJS-y)
+                       libxl_internal.o libxl_utils.o libxl_uuid.o 
libxl_json.o \
+                       $(LIBXL_OBJS-y)
 LIBXL_OBJS += _libxl_types.o libxl_flask.o _libxl_types_internal.o
 
 $(LIBXL_OBJS): CFLAGS += $(CFLAGS_libxenctrl) $(CFLAGS_libxenguest) 
$(CFLAGS_libxenstore) $(CFLAGS_libblktapctl)
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 71eb189..555d9f3 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -381,4 +381,101 @@ _hidden int libxl__e820_alloc(libxl_ctx *ctx, uint32_t 
domid, libxl_domain_confi
 #define STRINGIFY(x) #x
 #define TOSTRING(x) STRINGIFY(x)
 
+/* from libxl_json */
+typedef enum {
+    JSON_ERROR,
+    JSON_NULL,
+    JSON_TRUE,
+    JSON_FALSE,
+    JSON_INTEGER,
+    JSON_DOUBLE,
+    JSON_STRING,
+    JSON_MAP,
+    JSON_ARRAY,
+    JSON_ANY
+} libxl__json_node_type;
+
+typedef struct libxl__json_object {
+    libxl__json_node_type type;
+    union {
+        long i;
+        double d;
+        const char *string;
+        /* List of libxl__json_object */
+        flexarray_t *array;
+        /* List of libxl__json_map_node */
+        flexarray_t *map;
+    } u;
+    struct libxl__json_object *parent;
+} libxl__json_object;
+
+typedef struct {
+    const char *map_key;
+    libxl__json_object *obj;
+} libxl__json_map_node;
+
+typedef struct libxl__yajl_ctx libxl__yajl_ctx;
+
+static inline bool json_object_is_string(const libxl__json_object *o)
+{
+    return o != NULL && o->type == JSON_STRING;
+}
+static inline bool json_object_is_integer(const libxl__json_object *o)
+{
+    return o != NULL && o->type == JSON_INTEGER;
+}
+static inline bool json_object_is_map(const libxl__json_object *o)
+{
+    return o != NULL && o->type == JSON_MAP;
+}
+static inline bool json_object_is_array(const libxl__json_object *o)
+{
+    return o != NULL && o->type == JSON_ARRAY;
+}
+
+static inline const char *json_object_get_string(const libxl__json_object *o)
+{
+    if (json_object_is_string(o))
+        return o->u.string;
+    else
+        return NULL;
+}
+static inline flexarray_t *json_object_get_map(const libxl__json_object *o)
+{
+    if (json_object_is_map(o))
+        return o->u.map;
+    else
+        return NULL;
+}
+static inline flexarray_t *json_object_get_array(const libxl__json_object *o)
+{
+    if (json_object_is_array(o))
+        return o->u.array;
+    else
+        return NULL;
+}
+static inline long json_object_get_integer(const libxl__json_object *o)
+{
+    if (json_object_is_integer(o))
+        return o->u.i;
+    else
+        return -1;
+}
+
+_hidden const libxl__json_object *json_object_get(const char *key,
+                                          const libxl__json_object *o,
+                                          libxl__json_node_type expected_type);
+_hidden void json_object_free(libxl_ctx *ctx, libxl__json_object *obj);
+
+/* s: is the buffer to parse, libxl__json_parse will advance the pointer the
+ *    part that has not been parsed
+ * *yajl_ctx: is set if the buffer have been whole consume, but the JSON
+ *            structure is not complete.
+ * return NULL in case of error or when the JSON structure is not complete.
+ */
+_hidden libxl__json_object *libxl__json_parse(libxl_ctx *ctx,
+                                              libxl__yajl_ctx **yajl_ctx,
+                                              const unsigned char **s,
+                                              ssize_t len);
+
 #endif
diff --git a/tools/libxl/libxl_json.c b/tools/libxl/libxl_json.c
new file mode 100644
index 0000000..ff9a176
--- /dev/null
+++ b/tools/libxl/libxl_json.c
@@ -0,0 +1,521 @@
+/*
+ * Copyright (C) 2011      Citrix Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+
+#include <string.h>
+
+#include <yajl/yajl_parse.h>
+#include <yajl/yajl_gen.h>
+
+#include "libxl_internal.h"
+
+#define DEBUG_ANSWER
+
+struct libxl__yajl_ctx {
+    libxl_ctx *ctx;
+    yajl_handle hand;
+    libxl__json_object *head;
+    libxl__json_object *current;
+#ifdef DEBUG_ANSWER
+    yajl_gen g;
+#endif
+};
+
+#ifdef DEBUG_ANSWER
+#  define DEBUG_GEN_ALLOC(h) \
+    if (h == NULL) { \
+        yajl_gen_config conf = { 1, "  " }; \
+        h = yajl_gen_alloc(&conf, NULL); \
+    }
+#  define DEBUG_GEN_FREE(h)               if (h) yajl_gen_free(h)
+#  define DEBUG_GEN(h, type)              yajl_gen_##type(h)
+#  define DEBUG_GEN_VALUE(h, type, value) yajl_gen_##type(h, value)
+#  define DEBUG_GEN_STRING(h, str, n)     yajl_gen_string(h, str, n)
+#  define DEBUG_GEN_REPORT(h, ctx) \
+    do { \
+        const unsigned char *buf = NULL; \
+        unsigned int len = 0; \
+        yajl_gen_get_buf(h, &buf, &len); \
+        LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "response:\n%s", buf); \
+        yajl_gen_free(h); \
+        h = NULL; \
+    } while (0)
+#else
+#  define DEBUG_GEN_ALLOC(h)                  ((void)0)
+#  define DEBUG_GEN_FREE(h)                   ((void)0)
+#  define DEBUG_GEN(h, type)                  ((void)0)
+#  define DEBUG_GEN_VALUE(h, type, value)     ((void)0)
+#  define DEBUG_GEN_STRING(h, value, lenght)  ((void)0)
+#  define DEBUG_GEN_REPORT(h, ctx)            ((void)0)
+#endif
+
+/*
+ * libxl__json_object helper functions
+ */
+
+static libxl__json_object *json_object_alloc(libxl_ctx *ctx,
+                                             libxl__json_node_type type)
+{
+    libxl__json_object *obj;
+
+    obj = calloc(1, sizeof (libxl__json_object));
+    if (obj == NULL) {
+        LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR,
+                         "Failed to allocate a libxl__json_object");
+        return NULL;
+    }
+
+    obj->type = type;
+
+    if (type == JSON_MAP || type == JSON_ARRAY) {
+        flexarray_t *array = flexarray_make(1, 1);
+        if (array == NULL) {
+            LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR,
+                             "Failed to allocate a flexarray");
+            free(obj);
+            return NULL;
+        }
+        if (type == JSON_MAP)
+            obj->u.map = array;
+        else
+            obj->u.array = array;
+    }
+
+    return obj;
+}
+
+static int json_object_append_to(libxl_ctx *ctx,
+                                 libxl__json_object *obj,
+                                 libxl__json_object *dst)
+{
+    if (!dst) {
+        LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
+                   "No parent json object to fill");
+        return -1;
+    }
+
+    switch (dst->type) {
+    case JSON_MAP: {
+        libxl__json_map_node *last;
+
+        if (dst->u.map->count == 0) {
+            LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
+                       "Try to add a value to an empty map (with no key)");
+            return -1;
+        }
+        flexarray_get(dst->u.map, dst->u.map->count - 1, (void**)&last);
+        last->obj = obj;
+        break;
+    }
+    case JSON_ARRAY:
+        if (flexarray_append(dst->u.array, obj) == 2) {
+            LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR,
+                             "Failed to grow a flexarray");
+            return -1;
+        }
+        break;
+    default:
+        LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
+                   "Try append an object is not a map/array (%i)\n",
+                   dst->type);
+        return -1;
+    }
+
+    obj->parent = dst;
+    return 0;
+}
+
+void json_object_free(libxl_ctx *ctx, libxl__json_object *obj)
+{
+    int index = 0;
+
+    if (obj == NULL)
+        return;
+    switch (obj->type) {
+    case JSON_STRING:
+        free((void*)obj->u.string);
+        break;
+    case JSON_MAP: {
+        libxl__json_map_node *node = NULL;
+
+        for (index = 0; index < obj->u.map->count; index++) {
+            if (flexarray_get(obj->u.map, index, (void**)&node) != 0)
+                break;
+            json_object_free(ctx, node->obj);
+            free((void*)node->map_key);
+            free(node);
+            node = NULL;
+        }
+        flexarray_free(obj->u.map);
+        break;
+    }
+    case JSON_ARRAY: {
+        libxl__json_object *node = NULL;
+        break;
+
+        for (index = 0; index < obj->u.array->count; index++) {
+            if (flexarray_get(obj->u.array, index, (void**)&node) != 0)
+                break;
+            json_object_free(ctx, node);
+            node = NULL;
+        }
+        flexarray_free(obj->u.array);
+        break;
+    }
+    default:
+        break;
+    }
+    free(obj);
+}
+
+const libxl__json_object *json_object_get(const char *key,
+                                          const libxl__json_object *o,
+                                          libxl__json_node_type expected_type)
+{
+    flexarray_t *maps = NULL;
+    int index = 0;
+
+    if (json_object_is_map(o)) {
+        libxl__json_map_node *node = NULL;
+
+        maps = o->u.map;
+        for (index = 0; index < maps->count; index++) {
+            if (flexarray_get(maps, index, (void**)&node) != 0)
+                return NULL;
+            if (strcmp(key, node->map_key) == 0) {
+                if (expected_type == JSON_ANY
+                    || (node->obj && node->obj->type == expected_type)) {
+                    return node->obj;
+                } else {
+                    return NULL;
+                }
+            }
+        }
+    }
+    return NULL;
+}
+
+
+/*
+ * JSON callbacks
+ */
+
+static int json_callback_null(void *opaque)
+{
+    libxl__yajl_ctx *ctx = opaque;
+    libxl__json_object *obj;
+
+    DEBUG_GEN(ctx->g, null);
+
+    if ((obj = json_object_alloc(ctx->ctx, JSON_NULL)) == NULL)
+        return 0;
+
+    if (json_object_append_to(ctx->ctx, obj, ctx->current) == -1) {
+        json_object_free(ctx->ctx, obj);
+        return 0;
+    }
+
+    return 1;
+}
+
+static int json_callback_boolean(void *opaque, int boolean)
+{
+    libxl__yajl_ctx *ctx = opaque;
+    libxl__json_object *obj;
+
+    DEBUG_GEN_VALUE(ctx->g, bool, boolean);
+
+    if ((obj = json_object_alloc(ctx->ctx,
+                                 boolean ? JSON_TRUE : JSON_FALSE)) == NULL)
+        return 0;
+
+    if (json_object_append_to(ctx->ctx, obj, ctx->current) == -1) {
+        json_object_free(ctx->ctx, obj);
+        return 0;
+    }
+
+    return 1;
+}
+
+static int json_callback_integer(void *opaque, long value)
+{
+    libxl__yajl_ctx *ctx = opaque;
+    libxl__json_object *obj;
+
+    DEBUG_GEN_VALUE(ctx->g, integer, value);
+
+    if ((obj = json_object_alloc(ctx->ctx, JSON_INTEGER)) == NULL)
+        return 0;
+    obj->u.i = value;
+
+    if (json_object_append_to(ctx->ctx, obj, ctx->current) == -1) {
+        json_object_free(ctx->ctx, obj);
+        return 0;
+    }
+
+    return 1;
+}
+
+static int json_callback_double(void *opaque, double value)
+{
+    libxl__yajl_ctx *ctx = opaque;
+    libxl__json_object *obj;
+
+    DEBUG_GEN_VALUE(ctx->g, double, value);
+
+    if ((obj = json_object_alloc(ctx->ctx, JSON_DOUBLE)) == NULL)
+        return 0;
+    obj->u.d = value;
+
+    if (json_object_append_to(ctx->ctx, obj, ctx->current) == -1) {
+        json_object_free(ctx->ctx, obj);
+        return 0;
+    }
+
+    return 1;
+}
+
+static int json_callback_string(void *opaque, const unsigned char *str,
+                                unsigned int len)
+{
+    libxl__yajl_ctx *ctx = opaque;
+    char *t = malloc(len + 1);
+    libxl__json_object *obj = NULL;
+
+    if (t == NULL) {
+        LIBXL__LOG_ERRNO(ctx->ctx, LIBXL__LOG_ERROR, "Failed to allocate");
+        return 0;
+    }
+
+    DEBUG_GEN_STRING(ctx->g, str, len);
+
+    strncpy(t, (const char *) str, len);
+    t[len] = 0;
+
+    if ((obj = json_object_alloc(ctx->ctx, JSON_STRING)) == NULL) {
+        free(t);
+        return 0;
+    }
+    obj->u.string = t;
+
+    if (json_object_append_to(ctx->ctx, obj, ctx->current) == -1) {
+        json_object_free(ctx->ctx, obj);
+        return 0;
+    }
+
+    return 1;
+}
+
+static int json_callback_map_key(void *opaque, const unsigned char *str,
+                                 unsigned int len)
+{
+    libxl__yajl_ctx *ctx = opaque;
+    char *t = malloc(len + 1);
+    libxl__json_object *obj = ctx->current;
+
+    if (t == NULL) {
+        LIBXL__LOG_ERRNO(ctx->ctx, LIBXL__LOG_ERROR, "Failed to allocate");
+        return 0;
+    }
+
+    DEBUG_GEN_STRING(ctx->g, str, len);
+
+    strncpy(t, (const char *) str, len);
+    t[len] = 0;
+
+    if (json_object_is_map(obj)) {
+        libxl__json_map_node *node = malloc(sizeof (libxl__json_map_node));
+        if (node == NULL) {
+            LIBXL__LOG_ERRNO(ctx->ctx, LIBXL__LOG_ERROR,
+                             "Failed to allocate");
+            return 0;
+        }
+
+        node->map_key = t;
+        node->obj = NULL;
+
+        if (flexarray_append(obj->u.map, node) == 2) {
+            LIBXL__LOG_ERRNO(ctx->ctx, LIBXL__LOG_ERROR,
+                             "Failed to grow a flexarray");
+            return 0;
+        }
+    } else {
+        LIBXL__LOG(ctx->ctx, LIBXL__LOG_ERROR,
+                   "Current json object is not a map");
+        return 0;
+    }
+
+    return 1;
+}
+
+static int json_callback_start_map(void *opaque)
+{
+    libxl__yajl_ctx *ctx = opaque;
+    libxl__json_object *obj = NULL;
+
+    DEBUG_GEN(ctx->g, map_open);
+
+    if ((obj = json_object_alloc(ctx->ctx, JSON_MAP)) == NULL)
+        return 0;
+
+    if (ctx->current) {
+        if (json_object_append_to(ctx->ctx, obj, ctx->current) == -1) {
+            json_object_free(ctx->ctx, obj);
+            return 0;
+        }
+    }
+
+    ctx->current = obj;
+    if (ctx->head == NULL) {
+        ctx->head = obj;
+    }
+
+    return 1;
+}
+
+static int json_callback_end_map(void *opaque)
+{
+    libxl__yajl_ctx *ctx = opaque;
+
+    DEBUG_GEN(ctx->g, map_close);
+
+    if (ctx->current) {
+        ctx->current = ctx->current->parent;
+    } else {
+        LIBXL__LOG(ctx->ctx, LIBXL__LOG_ERROR,
+                   "No current libxl__json_object, cannot use his parent.");
+        return 0;
+    }
+
+    return 1;
+}
+
+static int json_callback_start_array(void *opaque)
+{
+    libxl__yajl_ctx *ctx = opaque;
+    libxl__json_object *obj = NULL;
+
+    DEBUG_GEN(ctx->g, array_open);
+
+    if ((obj = json_object_alloc(ctx->ctx, JSON_ARRAY)) == NULL)
+        return 0;
+
+    if (ctx->current) {
+        if (json_object_append_to(ctx->ctx, obj, ctx->current) == -1) {
+            json_object_free(ctx->ctx, obj);
+            return 0;
+        }
+    }
+
+    ctx->current = obj;
+    if (ctx->head == NULL) {
+        ctx->head = obj;
+    }
+
+    return 1;
+}
+
+static int json_callback_end_array(void *opaque)
+{
+    libxl__yajl_ctx *ctx = opaque;
+
+    DEBUG_GEN(ctx->g, array_close);
+
+    if (ctx->current) {
+        ctx->current = ctx->current->parent;
+    } else {
+        LIBXL__LOG(ctx->ctx, LIBXL__LOG_ERROR,
+                   "No current libxl__json_object, cannot use his parent.");
+        return 0;
+    }
+
+    return 1;
+}
+
+static yajl_callbacks callbacks = {
+    json_callback_null,
+    json_callback_boolean,
+    json_callback_integer,
+    json_callback_double,
+    NULL,
+    json_callback_string,
+    json_callback_start_map,
+    json_callback_map_key,
+    json_callback_end_map,
+    json_callback_start_array,
+    json_callback_end_array
+};
+
+static void yajl_ctx_free(libxl__yajl_ctx *yajl_ctx)
+{
+    if (yajl_ctx->hand)
+        yajl_free(yajl_ctx->hand);
+    DEBUG_GEN_FREE(yajl_ctx->g);
+}
+
+libxl__json_object *libxl__json_parse(libxl_ctx *ctx,
+                                      libxl__yajl_ctx **yajl_ctx_p,
+                                      const unsigned char **s,
+                                      ssize_t len)
+{
+    yajl_status status;
+    const unsigned char *bak_s = *s;
+    libxl__yajl_ctx *yajl_ctx = *yajl_ctx_p;
+
+    if (yajl_ctx == NULL) {
+        yajl_ctx = calloc(1, sizeof (libxl__yajl_ctx));
+        if (yajl_ctx == NULL) {
+            LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR,
+                             "Failed to allocate the parser context");
+            return NULL;
+        }
+        yajl_ctx->ctx = ctx;
+    }
+
+    DEBUG_GEN_ALLOC(yajl_ctx->g);
+    /* parse the input */
+    if (yajl_ctx->hand == NULL) {
+        /* allow comments */
+        yajl_parser_config cfg = { 1, 1 };
+        yajl_ctx->hand = yajl_alloc(&callbacks, &cfg, NULL, yajl_ctx);
+    }
+    status = yajl_parse(yajl_ctx->hand, *s, len);
+    *s += yajl_get_bytes_consumed(yajl_ctx->hand);
+
+    if (status != yajl_status_ok
+        && status != yajl_status_insufficient_data) {
+        unsigned char *str = yajl_get_error(yajl_ctx->hand, 1, bak_s, len);
+
+        LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "yajl error: %s", str);
+        yajl_free_error(yajl_ctx->hand, str);
+
+        json_object_free(ctx, yajl_ctx->head);
+        yajl_ctx_free(yajl_ctx);
+        *yajl_ctx_p = NULL;
+        return NULL;
+    }
+
+    if (status == yajl_status_ok) {
+        libxl__json_object *o = yajl_ctx->head;
+
+        DEBUG_GEN_REPORT(yajl_ctx->g, ctx);
+
+        yajl_ctx->head = NULL;
+
+        yajl_ctx_free(yajl_ctx);
+        *yajl_ctx_p = NULL;
+        return o;
+    }
+    *yajl_ctx_p = yajl_ctx;
+    return NULL;
+}
-- 
1.7.2.5


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.