]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-json: Define JSON tree data structure for representing arbitrary JSON data
authorStephan Bosch <stephan.bosch@open-xchange.com>
Wed, 7 Aug 2019 21:13:36 +0000 (23:13 +0200)
committeraki.tuomi <aki.tuomi@open-xchange.com>
Sat, 18 Nov 2023 18:58:04 +0000 (18:58 +0000)
src/lib-json/Makefile.am
src/lib-json/json-tree.new.c [new file with mode: 0644]
src/lib-json/json-tree.new.h [new file with mode: 0644]
src/lib-json/json-types.c
src/lib-json/json-types.h

index f67e94f9bb816742eddb0b35ccabf31e7bd986b0..2ce0ec99af0069ebd6e48195e69b615261cefb8d 100644 (file)
@@ -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 (file)
index 0000000..c3e33d1
--- /dev/null
@@ -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 (file)
index 0000000..873319b
--- /dev/null
@@ -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
index f7855a6f4da9152417a86037286276f290fcdadb..2ced07d6db5ce04b8d3cd3384680eb79d9a488ae 100644 (file)
@@ -24,9 +24,10 @@ static const char *json_content_type_names[] = {
        [JSON_CONTENT_TYPE_DATA] = "<DATA>",
        [JSON_CONTENT_TYPE_STREAM] = "<STREAM>",
        [JSON_CONTENT_TYPE_INTEGER] = "<INTEGER>",
+       [JSON_CONTENT_TYPE_TREE] = "<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];
 }
 
index e3d0efdb5b34481ecf9a611570758238a219e25b..454eb871c95ad0e20c3976720091acffdbd418e0 100644 (file)
@@ -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;
 };