| @@ -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 } } } } | |||