Add json_loadb() for decoding possibly non null-terminated strings
authorPetri Lehtinen <petri@digip.org>
Sun, 10 Apr 2011 17:54:52 +0000 (20:54 +0300)
committerPetri Lehtinen <petri@digip.org>
Sun, 10 Apr 2011 18:01:50 +0000 (21:01 +0300)
Thanks to Jonathan Landis for the initial patch.

doc/apiref.rst
src/jansson.h
src/load.c
test/.gitignore
test/suites/api/Makefile.am
test/suites/api/check-exports
test/suites/api/test_loadb.c [new file with mode: 0644]

index 91239c9..991ee5a 100644 (file)
@@ -771,6 +771,17 @@ affect especially the behavior of the decoder.
    information about the error. *flags* is currently unused, and
    should be set to 0.
 
+.. function:: json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error)
+
+   .. refcounting:: new
+
+   Decodes the JSON string *buffer*, whose length is *buflen*, and
+   returns the array or object it contains, or *NULL* on error, in
+   which case *error* is filled with information about the error. This
+   is similar to :func:`json_loads()` except that the string doesn't
+   need to be null-terminated. *flags* is currently unused, and should
+   be set to 0.
+
 .. function:: json_t *json_loadf(FILE *input, size_t flags, json_error_t *error)
 
    .. refcounting:: new
index eb021d3..03e9d5a 100644 (file)
@@ -217,6 +217,7 @@ json_t *json_deep_copy(json_t *value);
 /* loading, printing */
 
 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);
 
index 3cc7d0f..9933583 100644 (file)
@@ -867,6 +867,58 @@ out:
     return result;
 }
 
+typedef struct
+{
+    const char *data;
+    size_t len;
+    size_t pos;
+} buffer_data_t;
+
+static int buffer_get(void *data)
+{
+    char c;
+    buffer_data_t *stream = data;
+    if(stream->pos >= stream->len)
+      return EOF;
+
+    c = stream->data[stream->pos];
+    stream->pos++;
+    return (unsigned char)c;
+}
+
+json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error)
+{
+    lex_t lex;
+    json_t *result;
+    buffer_data_t stream_data;
+
+    (void)flags; /* unused */
+
+    stream_data.data = buffer;
+    stream_data.pos = 0;
+    stream_data.len = buflen;
+
+    if(lex_init(&lex, buffer_get, (void *)&stream_data))
+        return NULL;
+
+    jsonp_error_init(error, "<buffer>");
+
+    result = parse_json(&lex, error);
+    if(!result)
+        goto out;
+
+    lex_scan(&lex, error);
+    if(lex.token != TOKEN_EOF) {
+        error_set(error, &lex, "end of file expected");
+        json_decref(result);
+        result = NULL;
+    }
+
+out:
+    lex_close(&lex);
+    return result;
+}
+
 json_t *json_loadf(FILE *input, size_t flags, json_error_t *error)
 {
     lex_t lex;
index 7b11ea0..278e5f5 100644 (file)
@@ -6,6 +6,7 @@ suites/api/test_cpp
 suites/api/test_dump
 suites/api/test_equal
 suites/api/test_load
+suites/api/test_loadb
 suites/api/test_memory_funcs
 suites/api/test_number
 suites/api/test_object
index 0021f93..58c31c6 100644 (file)
@@ -6,6 +6,7 @@ check_PROGRAMS = \
        test_dump \
        test_equal \
        test_load \
+       test_loadb \
        test_memory_funcs \
        test_number \
        test_object \
@@ -17,6 +18,7 @@ test_array_SOURCES = test_array.c util.h
 test_copy_SOURCES = test_copy.c util.h
 test_dump_SOURCES = test_dump.c util.h
 test_load_SOURCES = test_load.c util.h
+test_loadb_SOURCES = test_loadb.c util.h
 test_memory_funcs_SOURCES = test_memory_funcs.c util.h
 test_number_SOURCES = test_number.c util.h
 test_object_SOURCES = test_object.c util.h
index 3dc4a9e..6df5a48 100755 (executable)
@@ -50,6 +50,7 @@ json_dump_file
 json_loads
 json_loadf
 json_load_file
+json_loadb
 json_equal
 json_copy
 json_deep_copy
diff --git a/test/suites/api/test_loadb.c b/test/suites/api/test_loadb.c
new file mode 100644 (file)
index 0000000..27ea575
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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 "util.h"
+
+int main()
+{
+    json_t *json;
+    json_error_t error;
+    const char str[] = "[\"A\", {\"B\": \"C\"}, 1, 2, 3]garbage";
+    size_t len = strlen(str) - strlen("garbage");
+
+    json = json_loadb(str, len, 0, &error);
+    if(!json) {
+        fail("json_loadb failed on a valid JSON buffer");
+    }
+    json_decref(json);
+
+    json = json_loadb(str, len - 1, 0, &error);
+    if (json) {
+        json_decref(json);
+        fail("json_loadb should have failed on an incomplete buffer, but it didn't");
+    }
+    if(error.line != 1) {
+        fail("json_loadb returned an invalid line number on fail");
+    }
+    if(strcmp(error.text, "']' expected near end of file") != 0) {
+        fail("json_loadb returned an invalid error message for an unclosed top-level array");
+    }
+
+    return 0;
+}