From: Stephan Bosch Date: Wed, 7 Aug 2019 21:13:36 +0000 (+0200) Subject: lib-json: Define JSON tree data structure for representing arbitrary JSON data X-Git-Tag: 2.4.0~2383 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b2d7ec573391c9593d1402f4d6ee788ca3211994;p=thirdparty%2Fdovecot%2Fcore.git lib-json: Define JSON tree data structure for representing arbitrary JSON data --- diff --git a/src/lib-json/Makefile.am b/src/lib-json/Makefile.am index f67e94f9bb..2ce0ec99af 100644 --- a/src/lib-json/Makefile.am +++ b/src/lib-json/Makefile.am @@ -7,6 +7,7 @@ AM_CPPFLAGS = \ libjson_la_SOURCES = \ json-syntax.c \ json-types.c \ + json-tree.new.c \ json-parser.new.c \ json-generator.c \ json-istream.c \ @@ -16,6 +17,7 @@ libjson_la_LIBADD = -lm headers = \ json-syntax.h \ json-types.h \ + json-tree.new.h \ json-parser.new.h \ json-generator.h \ json-istream.h \ diff --git a/src/lib-json/json-tree.new.c b/src/lib-json/json-tree.new.c new file mode 100644 index 0000000000..c3e33d1976 --- /dev/null +++ b/src/lib-json/json-tree.new.c @@ -0,0 +1,607 @@ +/* Copyright (c) 2017-2023 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "llist.h" +#include "array.h" +#include "istream.h" + +#include "json-tree.new.h" + +struct json_tree_node_list { + struct json_tree_node *head, *tail; + unsigned int count; +}; + +struct json_tree_node { + struct json_tree *tree; + struct json_tree_node *parent, *prev, *next; + + struct json_node node; +}; + +struct json_tree { + struct json_tree_node node; + + pool_t pool; + int refcount; + + ARRAY_TYPE(json_tree) subtrees; + ARRAY(struct istream *) istreams; +}; + +/* + * Tree object + */ + +struct json_tree *json_tree_create_pool(pool_t pool) +{ + struct json_tree *jtree; + + pool_ref(pool); + + jtree = p_new(pool, struct json_tree, 1); + jtree->refcount = 1; + jtree->pool = pool; + + jtree->node.tree = jtree; + jtree->node.node.type = JSON_TYPE_NONE; + jtree->node.node.value.content_type = JSON_CONTENT_TYPE_NONE; + + return jtree; +} + +struct json_tree *json_tree_create(void) +{ + struct json_tree *jtree; + pool_t pool; + + pool = pool_alloconly_create("json tree", 1024); + jtree = json_tree_create_pool(pool); + pool_unref(&pool); + + return jtree; +} + +void json_tree_ref(struct json_tree *jtree) +{ + i_assert(jtree->refcount > 0); + jtree->refcount++; +} + +void json_tree_unref(struct json_tree **_jtree) +{ + struct json_tree *jtree = *_jtree; + + if (jtree == NULL) + return; + *_jtree = NULL; + + i_assert(jtree->refcount > 0); + if (--jtree->refcount > 0) + return; + + if (array_is_created(&jtree->subtrees)) { + struct json_tree **subtree_idx; + array_foreach_modifiable(&jtree->subtrees, subtree_idx) + json_tree_unref(subtree_idx); + array_free(&jtree->subtrees); + } + if (array_is_created(&jtree->istreams)) { + struct istream **istream_idx; + array_foreach_modifiable(&jtree->istreams, istream_idx) + i_stream_unref(istream_idx); + array_free(&jtree->istreams); + } + pool_unref(&jtree->pool); +} + +bool json_tree_is_object(const struct json_tree *jtree) +{ + return json_node_is_object(&jtree->node.node); +} + +bool json_tree_is_array(const struct json_tree *jtree) +{ + return json_node_is_array(&jtree->node.node); +} + +bool json_tree_is_string(const struct json_tree *jtree) +{ + return json_node_is_string(&jtree->node.node); +} + +bool json_tree_is_number(const struct json_tree *jtree) +{ + return json_node_is_number(&jtree->node.node); +} + +bool json_tree_is_true(const struct json_tree *jtree) +{ + return json_node_is_true(&jtree->node.node); +} + +bool json_tree_is_false(const struct json_tree *jtree) +{ + return json_node_is_false(&jtree->node.node); +} + +bool json_tree_is_boolean(const struct json_tree *jtree) +{ + return json_node_is_boolean(&jtree->node.node); +} + +bool json_tree_is_null(const struct json_tree *jtree) +{ + return json_node_is_null(&jtree->node.node); +} + +/* + * Tree node + */ + +static inline struct json_tree_node_list * +json_tree_node_create_list(struct json_tree_node *jtnode) +{ + i_assert(jtnode->node.type == JSON_TYPE_OBJECT || + jtnode->node.type == JSON_TYPE_ARRAY); + i_assert(jtnode->node.value.content_type == JSON_CONTENT_TYPE_LIST); + if (jtnode->node.value.content.list == NULL) { + jtnode->node.value.content.list = + p_new(jtnode->tree->pool, + struct json_tree_node_list, 1); + } + return jtnode->node.value.content.list; +} + +struct json_tree_node *json_tree_get_root(struct json_tree *jtree) +{ + return &jtree->node; +} + +const struct json_tree_node * +json_tree_get_root_const(const struct json_tree *jtree) +{ + return &jtree->node; +} + +static struct json_tree_node * +json_tree_node_create(struct json_tree_node *parent, const char *name) +{ + struct json_tree *jtree = parent->tree; + struct json_tree_node_list *list; + struct json_tree_node *jtnode; + + i_assert(name != NULL || parent->node.type != JSON_TYPE_OBJECT); + + if (parent == &jtree->node && parent->node.type == JSON_TYPE_NONE) { + /* We're substituting the root (name is ignored) */ + i_assert(parent->node.value.content_type == + JSON_CONTENT_TYPE_NONE); + jtnode = &jtree->node; + i_zero(jtnode); + } else { + /* We're creating a new node */ + jtnode = p_new(jtree->pool, struct json_tree_node, 1); + jtnode->node.name = (name == NULL ? + NULL : p_strdup(jtree->pool, name)); + jtnode->parent = parent; + list = json_tree_node_create_list(parent); + DLLIST2_APPEND(&list->head, &list->tail, jtnode); + list->count++; + } + + jtnode->tree = jtree; + return jtnode; +} + +/* node */ + +struct json_tree_node * +json_tree_node_add(struct json_tree_node *parent, + const struct json_node *jnode) +{ + return json_tree_node_add_value(parent, jnode->name, jnode->type, + &jnode->value); +} + +/* object, array */ + +struct json_tree_node * +json_tree_node_add_object(struct json_tree_node *parent, const char *name) +{ + struct json_tree_node *jtnode; + + jtnode = json_tree_node_create(parent, name); + jtnode->node.type = JSON_TYPE_OBJECT; + jtnode->node.value.content_type = JSON_CONTENT_TYPE_LIST; + jtnode->node.value.content.list = NULL; + + return jtnode; +} + +struct json_tree_node * +json_tree_node_add_array(struct json_tree_node *parent, const char *name) +{ + struct json_tree_node *jtnode; + + jtnode = json_tree_node_create(parent, name); + jtnode->node.type = JSON_TYPE_ARRAY; + jtnode->node.value.content_type = JSON_CONTENT_TYPE_LIST; + jtnode->node.value.content.list = NULL; + + return jtnode; +} + +/* value */ + +struct json_tree_node * +json_tree_node_add_value(struct json_tree_node *parent, const char *name, + enum json_type type, const struct json_value *jvalue) +{ + struct json_tree *jtree = parent->tree; + struct json_tree_node *jtnode; + struct json_data *jdata; + unsigned char *data; + + jtnode = json_tree_node_create(parent, name); + jtnode->node.type = type; + jtnode->node.value = *jvalue; + switch (jvalue->content_type) { + case JSON_CONTENT_TYPE_NONE: + break; + case JSON_CONTENT_TYPE_LIST: + /* Equivalent to calling json_tree_node_add_array() or + json_tree_node_add_object(); doesn't copy list */ + jtnode->node.value.content.list = NULL; + break; + case JSON_CONTENT_TYPE_STRING: + jtnode->node.value.content.str = + p_strdup(jtree->pool, jvalue->content.str); + break; + case JSON_CONTENT_TYPE_DATA: + jdata = p_new(jtree->pool, struct json_data, 1); + *jdata = *jvalue->content.data; + data = p_malloc(jtree->pool, jdata->size + 1); + jdata->data = memcpy(data, jdata->data, jdata->size); + jtnode->node.value.content.data = jdata; + break; + case JSON_CONTENT_TYPE_STREAM: + if (!array_is_created(&jtree->istreams)) + i_array_init(&jtree->istreams, 4); + array_append(&jtree->istreams, &jvalue->content.stream, 1); + i_stream_ref(jvalue->content.stream); + break; + case JSON_CONTENT_TYPE_INTEGER: + break; + case JSON_CONTENT_TYPE_TREE: + i_assert(jvalue->content.tree != jtree); + if (!array_is_created(&jtree->subtrees)) + i_array_init(&jtree->subtrees, 4); + array_append(&jtree->subtrees, &jvalue->content.tree, 1); + json_tree_ref(jvalue->content.tree); + break; + } + + return jtnode; +} + +/* string */ + +struct json_tree_node * +json_tree_node_add_string(struct json_tree_node *parent, const char *name, + const char *str) +{ + struct json_value jvalue; + + i_zero(&jvalue); + jvalue.content_type = JSON_CONTENT_TYPE_STRING; + jvalue.content.str = str; + return json_tree_node_add_value(parent, name, JSON_TYPE_STRING, + &jvalue); +} + +struct json_tree_node * +json_tree_node_add_data(struct json_tree_node *parent, const char *name, + const unsigned char *data, size_t size) +{ + struct json_value jvalue; + struct json_data jdata; + + i_zero(&data); + jdata.data = data; + jdata.size = size; + + i_zero(&jvalue); + jvalue.content_type = JSON_CONTENT_TYPE_DATA; + jvalue.content.data = &jdata; + return json_tree_node_add_value(parent, name, JSON_TYPE_STRING, + &jvalue); +} + +struct json_tree_node * +json_tree_node_add_string_stream(struct json_tree_node *parent, + const char *name, struct istream *input) +{ + struct json_value jvalue; + + i_zero(&jvalue); + jvalue.content_type = JSON_CONTENT_TYPE_STREAM; + jvalue.content.stream = input; + return json_tree_node_add_value(parent, name, JSON_TYPE_STRING, + &jvalue); +} + +/* number */ + +struct json_tree_node * +json_tree_node_add_number_int(struct json_tree_node *parent, const char *name, + uintmax_t num) +{ + struct json_value jvalue; + + i_zero(&jvalue); + jvalue.content_type = JSON_CONTENT_TYPE_INTEGER; + jvalue.content.intnum = num; + return json_tree_node_add_value(parent, name, JSON_TYPE_NUMBER, + &jvalue); +} + +struct json_tree_node * +json_tree_node_add_number_str(struct json_tree_node *parent, const char *name, + const char *num) +{ + struct json_value jvalue; + + i_zero(&jvalue); + jvalue.content_type = JSON_CONTENT_TYPE_STRING; + jvalue.content.str = num; + return json_tree_node_add_value(parent, name, JSON_TYPE_NUMBER, + &jvalue); +} + +/* false, true */ + +struct json_tree_node * +json_tree_node_add_false(struct json_tree_node *parent, const char *name) +{ + struct json_value jvalue; + + i_zero(&jvalue); + return json_tree_node_add_value(parent, name, JSON_TYPE_FALSE, + &jvalue); +} + +struct json_tree_node * +json_tree_node_add_true(struct json_tree_node *parent, const char *name) +{ + struct json_value jvalue; + + i_zero(&jvalue); + return json_tree_node_add_value(parent, name, JSON_TYPE_TRUE, + &jvalue); +} + +struct json_tree_node * +json_tree_node_add_boolean(struct json_tree_node *parent, const char *name, + bool val) +{ + struct json_value jvalue; + + i_zero(&jvalue); + return json_tree_node_add_value( + parent, name, (val ? JSON_TYPE_TRUE : JSON_TYPE_FALSE), + &jvalue); +} + +/* null */ + +struct json_tree_node * +json_tree_node_add_null(struct json_tree_node *parent, const char *name) +{ + struct json_value jvalue; + + i_zero(&jvalue); + return json_tree_node_add_value(parent, name, JSON_TYPE_NULL, + &jvalue); +} + +/* JSON-text */ + +struct json_tree_node * +json_tree_node_add_text(struct json_tree_node *parent, const char *name, + const char *literal) +{ + struct json_value jvalue; + + i_zero(&jvalue); + jvalue.content_type = JSON_CONTENT_TYPE_STRING; + jvalue.content.str = literal; + return json_tree_node_add_value(parent, name, JSON_TYPE_TEXT, &jvalue); +} + +struct json_tree_node * +json_tree_node_add_text_data(struct json_tree_node *parent, const char *name, + const unsigned char *data, size_t size) +{ + struct json_value jvalue; + struct json_data jdata; + + i_zero(&jdata); + jdata.data = data; + jdata.size = size; + + i_zero(&jvalue); + jvalue.content_type = JSON_CONTENT_TYPE_DATA; + jvalue.content.data = &jdata; + return json_tree_node_add_value(parent, name, JSON_TYPE_TEXT, &jvalue); +} + +struct json_tree_node * +json_tree_node_add_subtree(struct json_tree_node *parent, const char *name, + struct json_tree *tree) +{ + struct json_value jvalue; + + i_zero(&jvalue); + jvalue.content_type = JSON_CONTENT_TYPE_TREE; + jvalue.content.tree = tree; + return json_tree_node_add_value(parent, name, JSON_TYPE_TEXT, &jvalue); +} + +/* + * Tree inspection + */ + +enum json_type json_tree_node_get_type(const struct json_tree_node *jtnode) +{ + return jtnode->node.type; +} + +const char *json_tree_node_get_name(const struct json_tree_node *jtnode) +{ + return jtnode->node.name; +} + +struct json_tree * +json_tree_node_get_tree(struct json_tree_node *jtnode) +{ + return jtnode->tree; +} + +const struct json_tree * +json_tree_node_get_tree_const(const struct json_tree_node *jtnode) +{ + return jtnode->tree; +} + +bool json_tree_node_is_root(const struct json_tree_node *jtnode) +{ + return (json_tree_get_root(jtnode->tree) == jtnode); +} + +bool json_tree_node_is_object(const struct json_tree_node *jtnode) +{ + return json_node_is_object(&jtnode->node); +} + +bool json_tree_node_is_array(const struct json_tree_node *jtnode) +{ + return json_node_is_array(&jtnode->node); +} + +bool json_tree_node_is_string(const struct json_tree_node *jtnode) +{ + return json_node_is_string(&jtnode->node); +} + +bool json_tree_node_is_number(const struct json_tree_node *jtnode) +{ + return json_node_is_number(&jtnode->node); +} + +bool json_tree_node_is_true(const struct json_tree_node *jtnode) +{ + return json_node_is_true(&jtnode->node); +} + +bool json_tree_node_is_false(const struct json_tree_node *jtnode) +{ + return json_node_is_false(&jtnode->node); +} + +bool json_tree_node_is_boolean(const struct json_tree_node *jtnode) +{ + return json_node_is_boolean(&jtnode->node); +} + +bool json_tree_node_is_null(const struct json_tree_node *jtnode) +{ + return json_node_is_null(&jtnode->node); +} + +const struct json_node * +json_tree_node_get(const struct json_tree_node *jtnode) +{ + return &jtnode->node; +} + +struct json_tree_node * +json_tree_node_get_next(const struct json_tree_node *jtnode) +{ + return jtnode->next; +} + +struct json_tree_node * +json_tree_node_get_parent(const struct json_tree_node *jtnode) +{ + return jtnode->parent; +} + +struct json_tree_node * +json_tree_node_get_child(const struct json_tree_node *jtnode) +{ + i_assert(jtnode->node.value.content_type == JSON_CONTENT_TYPE_LIST); + if (jtnode->node.value.content.list == NULL) + return NULL; + return jtnode->node.value.content.list->head; +} + +unsigned int +json_tree_node_get_child_count(const struct json_tree_node *jtnode) +{ + i_assert(jtnode->node.value.content_type == JSON_CONTENT_TYPE_LIST); + if (jtnode->node.value.content.list == NULL) + return 0; + return jtnode->node.value.content.list->count; +} + +struct json_tree_node * +json_tree_node_get_member(const struct json_tree_node *jtnode, + const char *name) +{ + struct json_tree_node *child; + + i_assert(json_node_is_object(&jtnode->node)); + i_assert(jtnode->node.value.content_type == JSON_CONTENT_TYPE_LIST); + + if (jtnode->node.value.content.list == NULL) + return NULL; + + child = jtnode->node.value.content.list->head; + while (child != NULL) { + if (strcmp(child->node.name, name) == 0) + return child; + child = child->next; + } + return NULL; +} + +struct json_tree_node * +json_tree_node_get_child_with(const struct json_tree_node *jtnode, + const char *key, const char *value) +{ + struct json_tree_node *child; + + i_assert(jtnode->node.value.content_type == JSON_CONTENT_TYPE_LIST); + if (jtnode->node.value.content.list == NULL) + return NULL; + + child = jtnode->node.value.content.list->head; + while (child != NULL) { + struct json_tree_node *member; + + if (!json_node_is_object(&child->node)) + continue; + member = json_tree_node_get_member(child, key); + if (member == NULL) + continue; + if (!json_tree_node_is_string(member)) + continue; + if (strcmp(json_tree_node_get_str(member), value) == 0) + break; + + child = child->next; + } + + return child; +} diff --git a/src/lib-json/json-tree.new.h b/src/lib-json/json-tree.new.h new file mode 100644 index 0000000000..873319b12f --- /dev/null +++ b/src/lib-json/json-tree.new.h @@ -0,0 +1,257 @@ +#ifndef JSON_TREE_H +#define JSON_TREE_H + +#include "json-types.h" + +struct json_tree; + +ARRAY_DEFINE_TYPE(json_tree, struct json_tree *); +ARRAY_DEFINE_TYPE(json_tree_node, struct json_tree_node *); +ARRAY_DEFINE_TYPE(json_tree_node_const, const struct json_tree_node *); + +/* + * Tree construction + */ + +/* node */ +struct json_tree_node * +json_tree_node_add(struct json_tree_node *parent, + const struct json_node *node); + +/* object, array */ +struct json_tree_node * +json_tree_node_add_object(struct json_tree_node *parent, const char *name); +struct json_tree_node * +json_tree_node_add_array(struct json_tree_node *parent, const char *name); + +/* value */ +struct json_tree_node * +json_tree_node_add_value(struct json_tree_node *parent, const char *name, + enum json_type type, + const struct json_value *value); + +/* string */ +struct json_tree_node * +json_tree_node_add_string(struct json_tree_node *parent, const char *name, + const char *str); +struct json_tree_node * +json_tree_node_add_data(struct json_tree_node *parent, const char *name, + const unsigned char *data, size_t size); +struct json_tree_node * +json_tree_node_add_string_stream(struct json_tree_node *parent, + const char *name, struct istream *input); + +/* number */ +struct json_tree_node * +json_tree_node_add_number_int(struct json_tree_node *parent, const char *name, + uintmax_t num); +struct json_tree_node * +json_tree_node_add_number_str(struct json_tree_node *parent, const char *name, + const char *num); + +/* false, true */ +struct json_tree_node * +json_tree_node_add_false(struct json_tree_node *parent, const char *name); +struct json_tree_node * +json_tree_node_add_true(struct json_tree_node *parent, const char *name); +struct json_tree_node * +json_tree_node_add_boolean(struct json_tree_node *parent, const char *name, + bool val); + +/* null */ +struct json_tree_node * +json_tree_node_add_null(struct json_tree_node *parent, const char *name); + +/* JSON-text */ + +struct json_tree_node * +json_tree_node_add_text(struct json_tree_node *parent, const char *name, + const char *literal); +struct json_tree_node * +json_tree_node_add_text_data(struct json_tree_node *parent, const char *name, + const unsigned char *data, size_t size); + +struct json_tree_node * +json_tree_node_add_subtree(struct json_tree_node *parent, const char *name, + struct json_tree *tree); + +/* + * Tree inspection + */ + +enum json_type +json_tree_node_get_type(const struct json_tree_node *jtnode) ATTR_PURE; +const char * +json_tree_node_get_name(const struct json_tree_node *jtnode) ATTR_PURE; +struct json_tree * +json_tree_node_get_tree(struct json_tree_node *jtnode) ATTR_PURE; +const struct json_tree * +json_tree_node_get_tree_const(const struct json_tree_node *jtnode) ATTR_PURE; + +bool json_tree_node_is_root(const struct json_tree_node *jtnode) ATTR_PURE; + +bool json_tree_node_is_object(const struct json_tree_node *njtode) ATTR_PURE; +bool json_tree_node_is_array(const struct json_tree_node *jtnode) ATTR_PURE; +bool json_tree_node_is_string(const struct json_tree_node *jtnode) ATTR_PURE; +bool json_tree_node_is_number(const struct json_tree_node *jtnode) ATTR_PURE; +bool json_tree_node_is_true(const struct json_tree_node *jtnode) ATTR_PURE; +bool json_tree_node_is_false(const struct json_tree_node *jtnode) ATTR_PURE; +bool json_tree_node_is_boolean(const struct json_tree_node *jtnode) ATTR_PURE; +bool json_tree_node_is_null(const struct json_tree_node *jtnode) ATTR_PURE; + +const struct json_node * +json_tree_node_get(const struct json_tree_node *jtnode) ATTR_PURE; + +struct json_tree_node * +json_tree_node_get_next(const struct json_tree_node *jtnode) ATTR_PURE; +struct json_tree_node * +json_tree_node_get_parent(const struct json_tree_node *jtnode) ATTR_PURE; +struct json_tree_node * +json_tree_node_get_child(const struct json_tree_node *jtnode) ATTR_PURE; +unsigned int +json_tree_node_get_child_count(const struct json_tree_node *jtnode) ATTR_PURE; + +struct json_tree_node * +json_tree_node_get_member(const struct json_tree_node *jtnode, + const char *name) ATTR_PURE; + +struct json_tree_node * +json_tree_node_get_child_with(const struct json_tree_node *jtnode, + const char *key, const char *value); + +static inline const char * +json_tree_node_get_str(const struct json_tree_node *jtnode) +{ + return json_node_get_str(json_tree_node_get(jtnode)); +} + +static inline const unsigned char * +json_tree_node_get_data(const struct json_tree_node *jtnode, size_t *size_r) +{ + return json_node_get_data(json_tree_node_get(jtnode), size_r); +} + +static inline const char * +json_tree_node_as_str(const struct json_tree_node *jtnode) +{ + return json_node_as_str(json_tree_node_get(jtnode)); +} + +static inline int +json_tree_node_get_intmax(const struct json_tree_node *jtnode, intmax_t *num_r) +{ + return json_node_get_intmax(json_tree_node_get(jtnode), num_r); +} + +static inline int +json_tree_node_get_int(const struct json_tree_node *jtnode, int *num_r) +{ + return json_node_get_int(json_tree_node_get(jtnode), num_r); +} + +static inline int +json_tree_node_get_long(const struct json_tree_node *jtnode, long *num_r) +{ + return json_node_get_long(json_tree_node_get(jtnode), num_r); +} + +static inline int +json_tree_node_get_llong(const struct json_tree_node *jtnode, long long *num_r) +{ + return json_node_get_llong(json_tree_node_get(jtnode), num_r); +} + +static inline int +json_tree_node_get_int32(const struct json_tree_node *jtnode, int32_t *num_r) +{ + return json_node_get_int32(json_tree_node_get(jtnode), num_r); +} + +static inline int +json_tree_node_get_int64(const struct json_tree_node *jtnode, int64_t *num_r) +{ + return json_node_get_int64(json_tree_node_get(jtnode), num_r); +} + +static inline int +json_tree_node_get_uintmax(const struct json_tree_node *jtnode, + uintmax_t *num_r) +{ + return json_node_get_uintmax(json_tree_node_get(jtnode), num_r); +} + +static inline int +json_tree_node_get_uint(const struct json_tree_node *jtnode, + unsigned int *num_r) +{ + return json_node_get_uint(json_tree_node_get(jtnode), num_r); +} + +static inline int +json_tree_node_get_ulong(const struct json_tree_node *jtnode, + unsigned long *num_r) +{ + return json_node_get_ulong(json_tree_node_get(jtnode), num_r); +} + +static inline int +json_tree_node_get_ullong(const struct json_tree_node *jtnode, + unsigned long long *num_r) +{ + return json_node_get_ullong(json_tree_node_get(jtnode), num_r); +} + +static inline int +json_tree_node_get_uint32(const struct json_tree_node *jtnode, uint32_t *num_r) +{ + return json_node_get_uint32(json_tree_node_get(jtnode), num_r); +} + +static inline int +json_tree_node_get_uint64(const struct json_tree_node *jtnode, uint64_t *num_r) +{ + return json_node_get_uint64(json_tree_node_get(jtnode), num_r); +} + +/* + * Tree object + */ + +struct json_tree_node *json_tree_get_root(struct json_tree *jtree); +const struct json_tree_node * +json_tree_get_root_const(const struct json_tree *jtree); + +struct json_tree *json_tree_create_pool(pool_t pool); +struct json_tree *json_tree_create(void); +void json_tree_ref(struct json_tree *jtree); +void json_tree_unref(struct json_tree **_jtree); + +static inline struct json_tree * +json_tree_create_object(struct json_tree_node **root_r) +{ + struct json_tree *jtree; + + jtree = json_tree_create(); + *root_r = json_tree_node_add_object(json_tree_get_root(jtree), NULL); + return jtree; +} +static inline struct json_tree * +json_tree_create_array(struct json_tree_node **root_r) +{ + struct json_tree *jtree; + + jtree = json_tree_create(); + *root_r = json_tree_node_add_array(json_tree_get_root(jtree), NULL); + return jtree; +} + +bool json_tree_is_object(const struct json_tree *jtree) ATTR_PURE; +bool json_tree_is_array(const struct json_tree *jtree) ATTR_PURE; +bool json_tree_is_string(const struct json_tree *jtree) ATTR_PURE; +bool json_tree_is_number(const struct json_tree *jtree) ATTR_PURE; +bool json_tree_is_true(const struct json_tree *jtree) ATTR_PURE; +bool json_tree_is_false(const struct json_tree *jtree) ATTR_PURE; +bool json_tree_is_boolean(const struct json_tree *jtree) ATTR_PURE; +bool json_tree_is_null(const struct json_tree *jtree) ATTR_PURE; + +#endif diff --git a/src/lib-json/json-types.c b/src/lib-json/json-types.c index f7855a6f4d..2ced07d6db 100644 --- a/src/lib-json/json-types.c +++ b/src/lib-json/json-types.c @@ -24,9 +24,10 @@ static const char *json_content_type_names[] = { [JSON_CONTENT_TYPE_DATA] = "", [JSON_CONTENT_TYPE_STREAM] = "", [JSON_CONTENT_TYPE_INTEGER] = "", + [JSON_CONTENT_TYPE_TREE] = "", }; static_assert_array_size(json_content_type_names, - JSON_CONTENT_TYPE_INTEGER + 1); + JSON_CONTENT_TYPE_TREE + 1); const char *json_type_get_name(enum json_type type) { @@ -36,7 +37,7 @@ const char *json_type_get_name(enum json_type type) const char *json_content_type_get_name(enum json_content_type ctype) { - i_assert(ctype <= JSON_CONTENT_TYPE_INTEGER); + i_assert(ctype <= JSON_CONTENT_TYPE_TREE); return json_content_type_names[ctype]; } diff --git a/src/lib-json/json-types.h b/src/lib-json/json-types.h index e3d0efdb5b..454eb871c9 100644 --- a/src/lib-json/json-types.h +++ b/src/lib-json/json-types.h @@ -3,6 +3,10 @@ #include "istream.h" +struct json_tree; +struct json_tree_node; +struct json_tree_node_list; + struct json_data; struct json_value; struct json_node; @@ -29,7 +33,7 @@ enum json_type { JSON_TYPE_FALSE, /* null */ JSON_TYPE_NULL, - /* JSON-text */ + /* JSON-text; either sub-tree or literal JSON text */ JSON_TYPE_TEXT, }; @@ -47,6 +51,8 @@ enum json_content_type { JSON_CONTENT_TYPE_STREAM, /* integer number */ JSON_CONTENT_TYPE_INTEGER, + /* sub-tree */ + JSON_CONTENT_TYPE_TREE, }; struct json_data { @@ -63,6 +69,8 @@ struct json_data { struct json_value { enum json_content_type content_type; union { + /* JSON2_CONTENT_TYPE_LIST */ + struct json_tree_node_list *list; /* only used by trees */ /* JSON_CONTENT_TYPE_STRING */ const char *str; /* JSON_CONTENT_TYPE_DATA */ @@ -71,6 +79,8 @@ struct json_value { struct istream *stream; /* JSON_CONTENT_TYPE_INTEGER */ intmax_t intnum; + /* JSON2_CONTENT_TYPE_TREE */ + struct json_tree *tree; } content; };