| @@ -82,6 +82,10 @@ void _json_c_set_last_err(const char *err_fmt, ...) | |||||
| } | } | ||||
| struct json_object* json_object_from_fd(int fd) | 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 printbuf *pb; | ||||
| struct json_object *obj; | 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"); | _json_c_set_last_err("json_object_from_file: printbuf_new failed\n"); | ||||
| return NULL; | 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) { | while((ret = read(fd, buf, JSON_FILE_BUF_SIZE)) > 0) { | ||||
| printbuf_memappend(pb, buf, ret); | printbuf_memappend(pb, buf, ret); | ||||
| } | } | ||||
| if(ret < 0) { | if(ret < 0) { | ||||
| _json_c_set_last_err("json_object_from_fd: error reading fd %d: %s\n", fd, strerror(errno)); | _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); | printbuf_free(pb); | ||||
| return NULL; | 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) | 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. | * Note, that the fd must be readable at the actual position, i.e. | ||||
| * use lseek(fd, 0, SEEK_SET) before. | * 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. | * 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); | 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 += $(TESTS:.test=.expected) | ||||
| EXTRA_DIST += test-defs.sh | EXTRA_DIST += test-defs.sh | ||||
| EXTRA_DIST += valid.json | EXTRA_DIST += valid.json | ||||
| EXTRA_DIST += valid_nested.json | |||||
| # Note: handled by test1.test | # Note: handled by test1.test | ||||
| @@ -5,6 +5,7 @@ | |||||
| #include <stddef.h> | #include <stddef.h> | ||||
| #include <string.h> | #include <string.h> | ||||
| #include <fcntl.h> | #include <fcntl.h> | ||||
| #include <limits.h> | |||||
| #include <unistd.h> | #include <unistd.h> | ||||
| #include <sys/types.h> | #include <sys/types.h> | ||||
| #include <sys/stat.h> | #include <sys/stat.h> | ||||
| @@ -13,6 +14,7 @@ | |||||
| #include "json_util.h" | #include "json_util.h" | ||||
| static void test_read_valid_with_fd(const char *testdir); | 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_nonexistant(); | ||||
| static void test_read_closed(void); | static void test_read_closed(void); | ||||
| @@ -129,6 +131,7 @@ int main(int argc, char **argv) | |||||
| testdir = argv[1]; | testdir = argv[1]; | ||||
| test_read_valid_with_fd(testdir); | test_read_valid_with_fd(testdir); | ||||
| test_read_valid_nested_with_fd(testdir); | |||||
| test_read_nonexistant(); | test_read_nonexistant(); | ||||
| test_read_closed(); | test_read_closed(); | ||||
| test_write_to_file(); | test_write_to_file(); | ||||
| @@ -137,7 +140,8 @@ int main(int argc, char **argv) | |||||
| static void test_read_valid_with_fd(const char *testdir) | 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); | int d = open(filename, O_RDONLY, 0); | ||||
| if (d < 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); | json_object *jso = json_object_from_fd(d); | ||||
| if (jso != NULL) | 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); | json_object_put(jso); | ||||
| } | } | ||||
| else | else | ||||
| @@ -160,6 +193,21 @@ static void test_read_valid_with_fd(const char *testdir) | |||||
| "FAIL: unable to parse contents of %s: %s\n", | "FAIL: unable to parse contents of %s: %s\n", | ||||
| filename, json_util_get_last_err()); | 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); | 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_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 | 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 } } } } | |||||