mirror of
https://github.com/json-c/json-c.git
synced 2026-03-13 18:19:06 +08:00
Add a json_object_from_fd_ex() function, to allow the max nesting depth to be specified.
This commit is contained in:
24
json_util.c
24
json_util.c
@@ -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,15 +96,33 @@ 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);
|
|
||||||
|
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);
|
printbuf_free(pb);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|||||||
12
json_util.h
12
json_util.h
@@ -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,8 @@ 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",
|
printf("OK: json_object_from_fd(valid.json)=%s\n",
|
||||||
filename, json_object_to_json_string(jso));
|
json_object_to_json_string(jso));
|
||||||
json_object_put(jso);
|
json_object_put(jso);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -163,6 +167,50 @@ static void test_read_valid_with_fd(const char *testdir)
|
|||||||
close(d);
|
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
|
||||||
|
{
|
||||||
|
fprintf(stderr,
|
||||||
|
"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);
|
||||||
|
}
|
||||||
|
|
||||||
static void test_read_nonexistant()
|
static void test_read_nonexistant()
|
||||||
{
|
{
|
||||||
const char *filename = "./not_present.json";
|
const char *filename = "./not_present.json";
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
1
tests/valid_nested.json
Normal file
1
tests/valid_nested.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"foo":123, "obj2": { "obj3": { "obj4": { "foo": 999 } } } }
|
||||||
Reference in New Issue
Block a user