Add json_load_callback()
authorRogerz Zhang <rogerz.zhang@gmail.com>
Wed, 21 Mar 2012 08:34:14 +0000 (16:34 +0800)
committerrogerz <rogerz.zhang@gmail.com>
Thu, 22 Mar 2012 06:52:57 +0000 (14:52 +0800)
src/jansson.h
src/load.c
test/suites/api/Makefile.am
test/suites/api/test_load_callback.c [new file with mode: 0644]

index 17885d4..8910e3d 100644 (file)
@@ -232,10 +232,13 @@ json_t *json_deep_copy(json_t *value);
 #define JSON_DISABLE_EOF_CHECK 0x2
 #define JSON_DECODE_ANY        0x4
 
+typedef int (*json_load_callback_t)(void *buffer, size_t buflen, void *arg);
+
 json_t *json_loads(const char *input, size_t flags, json_error_t *error);
 json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error);
 json_t *json_loadf(FILE *input, size_t flags, json_error_t *error);
 json_t *json_load_file(const char *path, size_t flags, json_error_t *error);
+json_t *json_load_callback(json_load_callback_t callback, void *arg, size_t flags, json_error_t *error);
 
 
 /* encoding */
index 70a1ac2..32d7901 100644 (file)
@@ -990,3 +990,58 @@ json_t *json_load_file(const char *path, size_t flags, json_error_t *error)
     fclose(fp);
     return result;
 }
+
+#define MAX_BUF_LEN 1024
+
+typedef struct
+{
+    char data[MAX_BUF_LEN];
+    size_t len;
+    size_t pos;
+    json_load_callback_t callback;
+    void *arg;
+} callback_data_t;
+
+static int callback_get(void *data)
+{
+    char c;
+    callback_data_t *stream = data;
+    
+    if(stream->pos >= stream->len) {
+        stream->pos = 0;
+        stream->len = stream->callback(stream->data, MAX_BUF_LEN, stream->arg);
+        if (stream->len <=0)
+            return EOF;
+    }
+
+    c = stream->data[stream->pos];
+    stream->pos++;
+    return (unsigned char)c;
+}
+
+json_t *json_load_callback(json_load_callback_t callback, void *arg, size_t flags, json_error_t *error)
+{
+    lex_t lex;
+    json_t *result;
+
+    callback_data_t stream_data;
+
+    memset(&stream_data, 0, sizeof(stream_data));
+    stream_data.callback = callback;
+    stream_data.arg = arg;
+
+    jsonp_error_init(error, "<callback>");
+
+    if (callback == NULL) {
+        error_set(error, NULL, "wrong arguments");
+        return NULL;
+    }
+
+    if(lex_init(&lex, (get_func)callback_get, &stream_data))
+        return NULL;
+
+    result = parse_json(&lex, flags, error);
+
+    lex_close(&lex);
+    return result;
+}
index 61a216f..9e60f48 100644 (file)
@@ -8,6 +8,7 @@ check_PROGRAMS = \
        test_equal \
        test_load \
        test_loadb \
+       test_load_callback \
        test_memory_funcs \
        test_number \
        test_object \
diff --git a/test/suites/api/test_load_callback.c b/test/suites/api/test_load_callback.c
new file mode 100644 (file)
index 0000000..33304dd
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include <jansson.h>
+#include <string.h>
+#include <stdlib.h>
+#include "util.h"
+
+struct my_source {
+    const char *buf;
+    size_t off;
+    size_t cap;
+};
+
+static const char my_str[] = "[\"A\", {\"B\": \"C\", \"e\": false}, 1, null, \"foo\"]";
+
+static int greedy_reader(void *buf, size_t buflen, void *arg)
+{
+    struct my_source *s = arg;
+    if (buflen > s->cap - s->off)
+        buflen = s->cap - s->off;
+    if (buflen > 0) {
+        memcpy(buf, s->buf + s->off, buflen);
+        s->off += buflen;
+        return buflen;
+    } else {
+        return 0;
+    }
+}
+
+static void run_tests()
+{
+    struct my_source s;
+    json_t *json;
+    json_error_t error;
+
+    s.off = 0;
+    s.cap = strlen(my_str);
+    s.buf = my_str;
+
+    json = json_load_callback(greedy_reader, &s, 0, &error);
+
+    if (!json)
+        fail("json_load_callback failed on a valid callback");
+    json_decref(json);
+
+    s.off = 0;
+    s.cap = strlen(my_str) - 1;
+    s.buf = my_str;
+
+    json = json_load_callback(greedy_reader, &s, 0, &error);
+    if (json) {
+        json_decref(json);
+        fail("json_load_callback should have failed on an incomplete stream, but it didn't");
+    }
+    if (strcmp(error.source, "<callback>") != 0) {
+        fail("json_load_callback returned an invalid error source");
+    }
+    if (strcmp(error.text, "']' expected near end of file") != 0) {
+        fail("json_load_callback returned an invalid error message for an unclosed top-level array");
+    }
+
+    json = json_load_callback(NULL, NULL, 0, &error);
+    if (json) {
+        json_decref(json);
+        fail("json_load_callback should have failed on NULL load callback, but it didn't");
+    }
+    if (strcmp(error.text, "wrong arguments") != 0) {
+        fail("json_load_callback returned an invalid error message for a NULL load callback");
+    }
+}