dovecot-2.2: lib: Added json-tree API for parsing JSON input int...
dovecot at dovecot.org
dovecot at dovecot.org
Wed Apr 8 04:56:59 UTC 2015
details: http://hg.dovecot.org/dovecot-2.2/rev/6bde7868cffd
changeset: 18399:6bde7868cffd
user: Timo Sirainen <tss at iki.fi>
date: Wed Apr 08 13:55:35 2015 +0900
description:
lib: Added json-tree API for parsing JSON input into a tree structure.
This makes it easier to access complicated JSON structs that can fit into
memory.
diffstat:
src/lib/Makefile.am | 3 +
src/lib/json-tree.c | 167 +++++++++++++++++++++++++++++++++++++++++++++++
src/lib/json-tree.h | 40 +++++++++++
src/lib/test-json-tree.c | 114 ++++++++++++++++++++++++++++++++
src/lib/test-lib.c | 1 +
src/lib/test-lib.h | 1 +
6 files changed, 326 insertions(+), 0 deletions(-)
diffs (truncated from 382 to 300 lines):
diff -r 8146fdc0de34 -r 6bde7868cffd src/lib/Makefile.am
--- a/src/lib/Makefile.am Mon Apr 06 12:07:32 2015 +0900
+++ b/src/lib/Makefile.am Wed Apr 08 13:55:35 2015 +0900
@@ -86,6 +86,7 @@
ioloop-epoll.c \
ioloop-kqueue.c \
json-parser.c \
+ json-tree.c \
lib.c \
lib-signals.c \
md4.c \
@@ -212,6 +213,7 @@
ioloop-private.h \
ioloop-notify-fd.h \
json-parser.h \
+ json-tree.h \
lib.h \
lib-signals.h \
llist.h \
@@ -301,6 +303,7 @@
test-istream-seekable.c \
test-istream-tee.c \
test-json-parser.c \
+ test-json-tree.c \
test-llist.c \
test-mempool-alloconly.c \
test-network.c \
diff -r 8146fdc0de34 -r 6bde7868cffd src/lib/json-tree.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/json-tree.c Wed Apr 08 13:55:35 2015 +0900
@@ -0,0 +1,167 @@
+/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "json-tree.h"
+
+struct json_tree {
+ pool_t pool;
+ struct json_tree_node *root, *cur, *cur_child;
+};
+
+struct json_tree *json_tree_init(void)
+{
+ struct json_tree *tree;
+ pool_t pool;
+
+ pool = pool_alloconly_create("json tree", 1024);
+ tree = p_new(pool, struct json_tree, 1);
+ tree->pool = pool;
+ tree->root = tree->cur = p_new(tree->pool, struct json_tree_node, 1);
+ tree->cur->value_type = JSON_TYPE_OBJECT;
+ return tree;
+}
+
+void json_tree_deinit(struct json_tree **_tree)
+{
+ struct json_tree *tree = *_tree;
+
+ *_tree = NULL;
+ pool_unref(&tree->pool);
+}
+
+static void
+json_tree_append_child(struct json_tree *tree, enum json_type type,
+ const char *value)
+{
+ struct json_tree_node *node;
+
+ node = p_new(tree->pool, struct json_tree_node, 1);
+ node->parent = tree->cur;
+ node->value_type = type;
+ node->value.str = p_strdup(tree->pool, value);
+
+ if (tree->cur_child == NULL)
+ tree->cur->value.child = node;
+ else
+ tree->cur_child->next = node;
+ tree->cur_child = node;
+}
+
+static void
+json_tree_set_cur(struct json_tree *tree, struct json_tree_node *node)
+{
+ tree->cur = node;
+ tree->cur_child = tree->cur->value.child;
+ if (tree->cur_child != NULL) {
+ while (tree->cur_child->next != NULL)
+ tree->cur_child = tree->cur_child->next;
+ }
+}
+
+static int
+json_tree_append_value(struct json_tree *tree, enum json_type type,
+ const char *value)
+{
+ switch (tree->cur->value_type) {
+ case JSON_TYPE_OBJECT_KEY:
+ /* "key": value - we already added the node and set its key,
+ so now just set the value */
+ tree->cur->value_type = type;
+ tree->cur->value.str = p_strdup(tree->pool, value);
+ json_tree_set_cur(tree, tree->cur->parent);
+ break;
+ case JSON_TYPE_ARRAY:
+ /* element in array - add a new node */
+ json_tree_append_child(tree, type, value);
+ break;
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+int json_tree_append(struct json_tree *tree, enum json_type type,
+ const char *value)
+{
+ switch (type) {
+ case JSON_TYPE_OBJECT_KEY:
+ if (tree->cur->value_type != JSON_TYPE_OBJECT)
+ return -1;
+ json_tree_append_child(tree, type, NULL);
+ json_tree_set_cur(tree, tree->cur_child);
+ tree->cur->key = p_strdup(tree->pool, value);
+ break;
+ case JSON_TYPE_ARRAY:
+ if (json_tree_append_value(tree, type, NULL) < 0)
+ return -1;
+ json_tree_set_cur(tree, tree->cur_child);
+ break;
+ case JSON_TYPE_OBJECT:
+ if (tree->cur->value_type == JSON_TYPE_OBJECT_KEY)
+ tree->cur->value_type = JSON_TYPE_OBJECT;
+ else if (tree->cur->value_type == JSON_TYPE_ARRAY) {
+ json_tree_append_child(tree, type, NULL);
+ json_tree_set_cur(tree, tree->cur_child);
+ } else {
+ return -1;
+ }
+ break;
+ case JSON_TYPE_OBJECT_END:
+ if (tree->cur->parent == NULL ||
+ tree->cur->value_type != JSON_TYPE_OBJECT)
+ return -1;
+ json_tree_set_cur(tree, tree->cur->parent);
+ break;
+ case JSON_TYPE_ARRAY_END:
+ if (tree->cur->parent == NULL ||
+ tree->cur->value_type != JSON_TYPE_ARRAY)
+ return -1;
+ json_tree_set_cur(tree, tree->cur->parent);
+ break;
+ case JSON_TYPE_STRING:
+ case JSON_TYPE_NUMBER:
+ case JSON_TYPE_TRUE:
+ case JSON_TYPE_FALSE:
+ case JSON_TYPE_NULL:
+ if (json_tree_append_value(tree, type, value) < 0)
+ return -1;
+ break;
+ }
+ return 0;
+}
+
+struct json_tree_node *json_tree_root(struct json_tree *tree)
+{
+ return tree->root;
+}
+
+struct json_tree_node *
+json_tree_find_key(struct json_tree_node *node, const char *key)
+{
+ for (; node != NULL; node = node->next) {
+ if (node->key != NULL && strcmp(node->key, key) == 0)
+ return node;
+ }
+ return NULL;
+}
+
+struct json_tree_node *
+json_tree_find_child_with(struct json_tree_node *node,
+ const char *key, const char *value)
+{
+ struct json_tree_node *child;
+
+ i_assert(node->value_type == JSON_TYPE_OBJECT ||
+ node->value_type == JSON_TYPE_ARRAY);
+
+ for (node = node->value.child; node != NULL; node = node->next) {
+ if (node->value_type != JSON_TYPE_OBJECT)
+ continue;
+
+ child = json_tree_find_key(node->value.child, key);
+ if (child != NULL && child->value.str != NULL &&
+ strcmp(child->value.str, value) == 0)
+ return node;
+ }
+ return NULL;
+}
diff -r 8146fdc0de34 -r 6bde7868cffd src/lib/json-tree.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/json-tree.h Wed Apr 08 13:55:35 2015 +0900
@@ -0,0 +1,40 @@
+#ifndef JSON_TREE_H
+#define JSON_TREE_H
+
+#include "json-parser.h"
+
+struct json_tree_node {
+ /* object key, or NULL if we're in a list */
+ const char *key;
+ struct json_tree_node *parent, *next;
+
+ enum json_type value_type;
+ struct {
+ /* for JSON_TYPE_OBJECT and JSON_TYPE_ARRAY */
+ struct json_tree_node *child;
+ /* for other types */
+ const char *str;
+ } value;
+};
+
+struct json_tree *json_tree_init(void);
+void json_tree_deinit(struct json_tree **tree);
+
+/* Append data to a tree. The type/value should normally come from json-parser.
+ Returns 0 on success, -1 if the input was invalid (which should never happen
+ if it's coming from json-parser). */
+int json_tree_append(struct json_tree *tree, enum json_type type,
+ const char *value);
+
+/* Return the root node. */
+struct json_tree_node *json_tree_root(struct json_tree *tree);
+/* Find a node with the specified key (from node's siblings) */
+struct json_tree_node *
+json_tree_find_key(struct json_tree_node *node, const char *key);
+/* Find an object node (from an array), which contains the specified key=value
+ in its values. */
+struct json_tree_node *
+json_tree_find_child_with(struct json_tree_node *node,
+ const char *key, const char *value);
+
+#endif
diff -r 8146fdc0de34 -r 6bde7868cffd src/lib/test-json-tree.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/test-json-tree.c Wed Apr 08 13:55:35 2015 +0900
@@ -0,0 +1,114 @@
+/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */
+
+#include "test-lib.h"
+#include "json-tree.h"
+
+struct {
+ enum json_type type;
+ const char *value;
+} test_input[] = {
+ { JSON_TYPE_OBJECT_KEY, "key-str" },
+ { JSON_TYPE_STRING, "string" },
+ { JSON_TYPE_OBJECT_KEY, "key-num" },
+ { JSON_TYPE_NUMBER, "1234" },
+ { JSON_TYPE_OBJECT_KEY, "key-true" },
+ { JSON_TYPE_TRUE, "true" },
+ { JSON_TYPE_OBJECT_KEY, "key-false" },
+ { JSON_TYPE_FALSE, "false" },
+ { JSON_TYPE_OBJECT_KEY, "key-null" },
+ { JSON_TYPE_NULL, NULL },
+
+ { JSON_TYPE_OBJECT_KEY, "key-obj-empty" },
+ { JSON_TYPE_OBJECT, NULL },
+ { JSON_TYPE_OBJECT_END, NULL },
+
+ { JSON_TYPE_OBJECT_KEY, "key-obj" },
+ { JSON_TYPE_OBJECT, NULL },
+ { JSON_TYPE_OBJECT_KEY, "sub" },
+ { JSON_TYPE_STRING, "value" },
+ { JSON_TYPE_OBJECT_END, NULL },
+
+ { JSON_TYPE_OBJECT_KEY, "key-arr-empty" },
+ { JSON_TYPE_ARRAY, NULL },
+ { JSON_TYPE_ARRAY_END, NULL },
+
+ { JSON_TYPE_OBJECT_KEY, "key-arr" },
+ { JSON_TYPE_ARRAY, NULL },
+ { JSON_TYPE_STRING, "foo" },
+ { JSON_TYPE_ARRAY, NULL },
+ { JSON_TYPE_TRUE, "true" },
+ { JSON_TYPE_ARRAY_END, NULL },
+ { JSON_TYPE_OBJECT, NULL },
+ { JSON_TYPE_OBJECT_KEY, "aobj" },
+ { JSON_TYPE_ARRAY, NULL },
+ { JSON_TYPE_ARRAY_END, NULL },
+ { JSON_TYPE_OBJECT_END, NULL },
+ { JSON_TYPE_OBJECT, NULL },
+ { JSON_TYPE_OBJECT_KEY, "aobj-key" },
+ { JSON_TYPE_STRING, "value1" },
+ { JSON_TYPE_OBJECT_END, NULL },
+ { JSON_TYPE_OBJECT, NULL },
+ { JSON_TYPE_OBJECT_KEY, "aobj-key" },
+ { JSON_TYPE_STRING, "value2" },
+ { JSON_TYPE_OBJECT_END, NULL },
+ { JSON_TYPE_ARRAY_END, NULL }
More information about the dovecot-cvs
mailing list