--- /dev/null
+/* 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;
+}
--- /dev/null
+#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