[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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |