WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

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

To: Xen Devel <xen-devel@xxxxxxxxxxxxxxxxxxx>
Subject: [Xen-devel] [PATCH V6 2/3] libxl: Introduce JSON parsing stuff.
From: Anthony PERARD <anthony.perard@xxxxxxxxxx>
Date: Thu, 30 Jun 2011 18:30:44 +0100
Cc: Ian Campbell <Ian.Campbell@xxxxxxxxxxxxx>, Anthony PERARD <anthony.perard@xxxxxxxxxx>, Stefano Stabellini <stefano.stabellini@xxxxxxxxxxxxx>
Delivery-date: Thu, 30 Jun 2011 10:32:54 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
In-reply-to: <1309455045-3062-1-git-send-email-anthony.perard@xxxxxxxxxx>
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
References: <1309455045-3062-1-git-send-email-anthony.perard@xxxxxxxxxx>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
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

<Prev in Thread] Current Thread [Next in Thread>