@@ -82,6 +82,10 @@ void _json_c_set_last_err(const char *err_fmt, ...) | |||
} | |||
struct json_object* json_object_from_fd(int fd) | |||
{ | |||
return json_object_from_fd_ex(fd, -1); | |||
} | |||
struct json_object* json_object_from_fd_ex(int fd, int in_depth) | |||
{ | |||
struct printbuf *pb; | |||
struct json_object *obj; | |||
@@ -92,17 +96,35 @@ struct json_object* json_object_from_fd(int fd) | |||
_json_c_set_last_err("json_object_from_file: printbuf_new failed\n"); | |||
return NULL; | |||
} | |||
int depth = JSON_TOKENER_DEFAULT_DEPTH; | |||
if (in_depth != -1) | |||
depth = in_depth; | |||
json_tokener *tok = json_tokener_new_ex(depth); | |||
if (!tok) | |||
{ | |||
_json_c_set_last_err("json_object_from_fd: unable to allocate json_tokener(depth=%d): %s\n", depth, strerror(errno)); | |||
printbuf_free(pb); | |||
return NULL; | |||
} | |||
while((ret = read(fd, buf, JSON_FILE_BUF_SIZE)) > 0) { | |||
printbuf_memappend(pb, buf, ret); | |||
} | |||
if(ret < 0) { | |||
_json_c_set_last_err("json_object_from_fd: error reading fd %d: %s\n", fd, strerror(errno)); | |||
json_tokener_free(tok); | |||
printbuf_free(pb); | |||
return NULL; | |||
} | |||
obj = json_tokener_parse(pb->buf); | |||
printbuf_free(pb); | |||
return obj; | |||
obj = json_tokener_parse_ex(tok, pb->buf, printbuf_length(pb)); | |||
if (obj == NULL) | |||
_json_c_set_last_err("json_tokener_parse_ex failed: %s\n", json_tokener_error_desc(json_tokener_get_error(tok))); | |||
json_tokener_free(tok); | |||
printbuf_free(pb); | |||
return obj; | |||
} | |||
struct json_object* json_object_from_file(const char *filename) | |||
@@ -50,8 +50,20 @@ JSON_EXPORT struct json_object* json_object_from_file(const char *filename); | |||
* Note, that the fd must be readable at the actual position, i.e. | |||
* use lseek(fd, 0, SEEK_SET) before. | |||
* | |||
* The depth argument specifies the maximum object depth to pass to | |||
* json_tokener_new_ex(). When depth == -1, JSON_TOKENER_DEFAULT_DEPTH | |||
* is used instead. | |||
* | |||
* Returns NULL on failure. See json_util_get_last_err() for details. | |||
*/ | |||
JSON_EXPORT struct json_object* json_object_from_fd_ex(int fd, int depth); | |||
/** | |||
* Create a JSON object from an already opened file descriptor, using | |||
* the default maximum object depth. (JSON_TOKENER_DEFAULT_DEPTH) | |||
* | |||
* See json_object_from_fd_ex() for details. | |||
*/ | |||
JSON_EXPORT struct json_object* json_object_from_fd(int fd); | |||
/** | |||
@@ -36,6 +36,7 @@ EXTRA_DIST += $(TESTS) | |||
EXTRA_DIST += $(TESTS:.test=.expected) | |||
EXTRA_DIST += test-defs.sh | |||
EXTRA_DIST += valid.json | |||
EXTRA_DIST += valid_nested.json | |||
# Note: handled by test1.test | |||
@@ -5,6 +5,7 @@ | |||
#include <stddef.h> | |||
#include <string.h> | |||
#include <fcntl.h> | |||
#include <limits.h> | |||
#include <unistd.h> | |||
#include <sys/types.h> | |||
#include <sys/stat.h> | |||
@@ -13,6 +14,7 @@ | |||
#include "json_util.h" | |||
static void test_read_valid_with_fd(const char *testdir); | |||
static void test_read_valid_nested_with_fd(const char *testdir); | |||
static void test_read_nonexistant(); | |||
static void test_read_closed(void); | |||
@@ -129,6 +131,7 @@ int main(int argc, char **argv) | |||
testdir = argv[1]; | |||
test_read_valid_with_fd(testdir); | |||
test_read_valid_nested_with_fd(testdir); | |||
test_read_nonexistant(); | |||
test_read_closed(); | |||
test_write_to_file(); | |||
@@ -137,7 +140,8 @@ int main(int argc, char **argv) | |||
static void test_read_valid_with_fd(const char *testdir) | |||
{ | |||
const char *filename = "./valid.json"; | |||
char filename[PATH_MAX]; | |||
(void)snprintf(filename, sizeof(filename), "%s/valid.json", testdir); | |||
int d = open(filename, O_RDONLY, 0); | |||
if (d < 0) | |||
@@ -150,8 +154,37 @@ static void test_read_valid_with_fd(const char *testdir) | |||
json_object *jso = json_object_from_fd(d); | |||
if (jso != NULL) | |||
{ | |||
printf("OK: json_object_from_fd(%s)=%s\n", | |||
filename, json_object_to_json_string(jso)); | |||
printf("OK: json_object_from_fd(valid.json)=%s\n", | |||
json_object_to_json_string(jso)); | |||
json_object_put(jso); | |||
} | |||
else | |||
{ | |||
fprintf(stderr, | |||
"FAIL: unable to parse contents of %s: %s\n", | |||
filename, json_util_get_last_err()); | |||
} | |||
close(d); | |||
} | |||
static void test_read_valid_nested_with_fd(const char *testdir) | |||
{ | |||
char filename[PATH_MAX]; | |||
(void)snprintf(filename, sizeof(filename), "%s/valid_nested.json", testdir); | |||
int d = open(filename, O_RDONLY, 0); | |||
if (d < 0) | |||
{ | |||
fprintf(stderr, | |||
"FAIL: unable to open %s: %s\n", | |||
filename, strerror(errno)); | |||
exit(EXIT_FAILURE); | |||
} | |||
json_object *jso = json_object_from_fd_ex(d, 20); | |||
if (jso != NULL) | |||
{ | |||
printf("OK: json_object_from_fd_ex(valid_nested.json, 20)=%s\n", | |||
json_object_to_json_string(jso)); | |||
json_object_put(jso); | |||
} | |||
else | |||
@@ -160,6 +193,21 @@ static void test_read_valid_with_fd(const char *testdir) | |||
"FAIL: unable to parse contents of %s: %s\n", | |||
filename, json_util_get_last_err()); | |||
} | |||
(void)lseek(d, SEEK_SET, 0); | |||
jso = json_object_from_fd_ex(d, 3); | |||
if (jso != NULL) | |||
{ | |||
printf("FAIL: json_object_from_fd_ex(%s, 3)=%s\n", | |||
filename, json_object_to_json_string(jso)); | |||
json_object_put(jso); | |||
} | |||
else | |||
{ | |||
printf("OK: correctly unable to parse contents of valid_nested.json with low max depth: %s\n", | |||
json_util_get_last_err()); | |||
} | |||
close(d); | |||
} | |||
@@ -1,4 +1,7 @@ | |||
OK: json_object_from_fd(./valid.json)={ "foo": 123 } | |||
OK: json_object_from_fd(valid.json)={ "foo": 123 } | |||
OK: json_object_from_fd_ex(valid_nested.json, 20)={ "foo": 123, "obj2": { "obj3": { "obj4": { "foo": 999 } } } } | |||
OK: correctly unable to parse contents of valid_nested.json with low max depth: json_tokener_parse_ex failed: nesting too deep | |||
OK: json_object_from_file(./not_present.json) correctly returned NULL: json_object_from_file: error opening file ./not_present.json: ERRNO=ENOENT | |||
OK: json_object_from_fd(closed_fd), expecting NULL, EBADF, got:NULL, json_object_from_fd: error reading fd 10: ERRNO=EBADF | |||
@@ -0,0 +1 @@ | |||
{"foo":123, "obj2": { "obj3": { "obj4": { "foo": 999 } } } } |