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

[Xen-devel] [PATCH V3 09/13] libxl_json: Handle number abrove LONG_MAX.



The integers are now "long long" in the json_object.

If a number (decimal or integer) is too big (or too low), it is stored as it in
a string. So for that, we introduce a new type JSON_NUMBER.

Signed-off-by: Anthony PERARD <anthony.perard@xxxxxxxxxx>
---
 tools/libxl/libxl_internal.h |    6 ++-
 tools/libxl/libxl_json.c     |   74 ++++++++++++++++++++++++++++++------------
 2 files changed, 57 insertions(+), 23 deletions(-)

diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 942d45b..09e0c51 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -468,6 +468,8 @@ typedef enum {
     JSON_FALSE,
     JSON_INTEGER,
     JSON_DOUBLE,
+    /* number is store in string, it's too big to be a long long or a double */
+    JSON_NUMBER,
     JSON_STRING,
     JSON_MAP,
     JSON_ARRAY,
@@ -477,7 +479,7 @@ typedef enum {
 typedef struct libxl__json_object {
     libxl__json_node_type type;
     union {
-        long i;
+        long long i;
         double d;
         char *string;
         /* List of libxl__json_object */
@@ -536,7 +538,7 @@ flexarray_t *libxl__json_object_get_array(const 
libxl__json_object *o)
     else
         return NULL;
 }
-static inline long libxl__json_object_get_integer(const libxl__json_object *o)
+static inline long long libxl__json_object_get_integer(const 
libxl__json_object *o)
 {
     if (libxl__json_object_is_integer(o))
         return o->u.i;
diff --git a/tools/libxl/libxl_json.c b/tools/libxl/libxl_json.c
index 389b697..fd5e2aa 100644
--- a/tools/libxl/libxl_json.c
+++ b/tools/libxl/libxl_json.c
@@ -14,6 +14,7 @@
 
 #include <assert.h>
 #include <string.h>
+#include <math.h>
 
 #include <yajl/yajl_parse.h>
 #include <yajl/yajl_gen.h>
@@ -44,6 +45,7 @@ struct libxl__yajl_ctx {
 #  define DEBUG_GEN(ctx, type)              yajl_gen_##type(ctx->g)
 #  define DEBUG_GEN_VALUE(ctx, type, value) yajl_gen_##type(ctx->g, value)
 #  define DEBUG_GEN_STRING(ctx, str, n)     yajl_gen_string(ctx->g, str, n)
+#  define DEBUG_GEN_NUMBER(ctx, str, n)     yajl_gen_number(ctx->g, str, n)
 #  define DEBUG_GEN_REPORT(yajl_ctx) \
     do { \
         const unsigned char *buf = NULL; \
@@ -60,6 +62,7 @@ struct libxl__yajl_ctx {
 #  define DEBUG_GEN(ctx, type)                  ((void)0)
 #  define DEBUG_GEN_VALUE(ctx, type, value)     ((void)0)
 #  define DEBUG_GEN_STRING(ctx, value, lenght)  ((void)0)
+#  define DEBUG_GEN_NUMBER(ctx, value, lenght)  ((void)0)
 #  define DEBUG_GEN_REPORT(ctx)                 ((void)0)
 #endif
 
@@ -363,6 +366,7 @@ void libxl__json_object_free(libxl__gc *gc, 
libxl__json_object *obj)
         return;
     switch (obj->type) {
     case JSON_STRING:
+    case JSON_NUMBER:
         free(obj->u.string);
         break;
     case JSON_MAP: {
@@ -504,36 +508,64 @@ static int json_callback_boolean(void *opaque, int 
boolean)
     return 1;
 }
 
-static int json_callback_integer(void *opaque, long value)
+static bool is_decimal(const char *s, unsigned len)
+{
+    const char *end = s + len;
+    for (; s < end; s++) {
+        if (*s == '.')
+            return true;
+    }
+    return false;
+}
+
+static int json_callback_number(void *opaque, const char *s, unsigned int len)
 {
     libxl__yajl_ctx *ctx = opaque;
-    libxl__json_object *obj;
+    libxl__json_object *obj = NULL;
+    char *t = NULL;
 
-    DEBUG_GEN_VALUE(ctx, integer, value);
+    DEBUG_GEN_NUMBER(ctx, s, len);
 
-    if ((obj = json_object_alloc(ctx->gc, JSON_INTEGER)) == NULL)
-        return 0;
-    obj->u.i = value;
+    if (is_decimal(s, len)) {
+        double d = strtod(s, NULL);
 
-    if (json_object_append_to(ctx->gc, obj, ctx->current) == -1) {
-        libxl__json_object_free(ctx->gc, obj);
-        return 0;
-    }
+        if ((d == HUGE_VAL || d == HUGE_VAL) && errno == ERANGE) {
+            goto error;
+        }
 
-    return 1;
-}
+        if ((obj = json_object_alloc(ctx->gc, JSON_DOUBLE)) == NULL)
+            return 0;
+        obj->u.d = d;
+    } else {
+        long long i = strtoll(s, NULL, 10);
 
-static int json_callback_double(void *opaque, double value)
-{
-    libxl__yajl_ctx *ctx = opaque;
-    libxl__json_object *obj;
+        if ((i == LLONG_MIN || i == LLONG_MAX) && errno == ERANGE) {
+            goto error;
+        }
 
-    DEBUG_GEN_VALUE(ctx, double, value);
+        if ((obj = json_object_alloc(ctx->gc, JSON_INTEGER)) == NULL)
+            return 0;
+        obj->u.i = i;
+    }
+    goto out;
 
-    if ((obj = json_object_alloc(ctx->gc, JSON_DOUBLE)) == NULL)
+error:
+    /* If the conversion fail, we just store the original string. */
+    if ((obj = json_object_alloc(ctx->gc, JSON_NUMBER)) == NULL)
         return 0;
-    obj->u.d = value;
 
+    t = malloc(len + 1);
+    if (t == NULL) {
+        LIBXL__LOG_ERRNO(libxl__gc_owner(ctx->gc), LIBXL__LOG_ERROR,
+                         "Failed to allocate");
+        return 0;
+    }
+    strncpy(t, s, len);
+    t[len] = 0;
+
+    obj->u.string = t;
+
+out:
     if (json_object_append_to(ctx->gc, obj, ctx->current) == -1) {
         libxl__json_object_free(ctx->gc, obj);
         return 0;
@@ -706,9 +738,9 @@ static int json_callback_end_array(void *opaque)
 static yajl_callbacks callbacks = {
     json_callback_null,
     json_callback_boolean,
-    json_callback_integer,
-    json_callback_double,
     NULL,
+    NULL,
+    json_callback_number,
     json_callback_string,
     json_callback_start_map,
     json_callback_map_key,
-- 
Anthony PERARD


_______________________________________________
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®.