From: Petri Lehtinen Date: Sun, 10 Apr 2011 17:54:52 +0000 (+0300) Subject: Add json_loadb() for decoding possibly non null-terminated strings X-Git-Tag: v2.1~12 X-Git-Url: http://www.project-moonshot.org/gitweb/?p=jansson.git;a=commitdiff_plain;h=b44e2be0322e4c68d290a75f6b0cf6eba2d5aab2 Add json_loadb() for decoding possibly non null-terminated strings Thanks to Jonathan Landis for the initial patch. --- diff --git a/doc/apiref.rst b/doc/apiref.rst index 91239c9..991ee5a 100644 --- a/doc/apiref.rst +++ b/doc/apiref.rst @@ -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 diff --git a/src/jansson.h b/src/jansson.h index eb021d3..03e9d5a 100644 --- a/src/jansson.h +++ b/src/jansson.h @@ -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); diff --git a/src/load.c b/src/load.c index 3cc7d0f..9933583 100644 --- a/src/load.c +++ b/src/load.c @@ -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, ""); + + 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; diff --git a/test/.gitignore b/test/.gitignore index 7b11ea0..278e5f5 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -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 diff --git a/test/suites/api/Makefile.am b/test/suites/api/Makefile.am index 0021f93..58c31c6 100644 --- a/test/suites/api/Makefile.am +++ b/test/suites/api/Makefile.am @@ -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 diff --git a/test/suites/api/check-exports b/test/suites/api/check-exports index 3dc4a9e..6df5a48 100755 --- a/test/suites/api/check-exports +++ b/test/suites/api/check-exports @@ -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 index 0000000..27ea575 --- /dev/null +++ b/test/suites/api/test_loadb.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2009-2011 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include +#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; +}