1 /* Copyright (c) 2015-2018 Dovecot authors, see the included COPYING file */
2 
3 #include "lib.h"
4 #include "json-tree.h"
5 
6 struct json_tree {
7 	pool_t pool;
8 	struct json_tree_node *root, *cur, *cur_child;
9 };
10 
11 struct json_tree *
json_tree_init_type(enum json_type container)12 json_tree_init_type(enum json_type container)
13 {
14 	struct json_tree *tree;
15 	pool_t pool;
16 
17 	pool = pool_alloconly_create("json tree", 1024);
18 	tree = p_new(pool, struct json_tree, 1);
19 	tree->pool = pool;
20 	tree->root = tree->cur = p_new(tree->pool, struct json_tree_node, 1);
21 	tree->cur->value_type = container == JSON_TYPE_ARRAY ? container : JSON_TYPE_OBJECT;
22 	return tree;
23 }
24 
json_tree_deinit(struct json_tree ** _tree)25 void json_tree_deinit(struct json_tree **_tree)
26 {
27 	struct json_tree *tree = *_tree;
28 
29 	*_tree = NULL;
30 	pool_unref(&tree->pool);
31 }
32 
33 static void
json_tree_append_child(struct json_tree * tree,enum json_type type,const char * value)34 json_tree_append_child(struct json_tree *tree, enum json_type type,
35 		       const char *value)
36 {
37 	struct json_tree_node *node;
38 
39 	node = p_new(tree->pool, struct json_tree_node, 1);
40 	node->parent = tree->cur;
41 	node->value_type = type;
42 	node->value.str = p_strdup(tree->pool, value);
43 
44 	if (tree->cur_child == NULL)
45 		tree->cur->value.child = node;
46 	else
47 		tree->cur_child->next = node;
48 	tree->cur_child = node;
49 }
50 
51 static void
json_tree_set_cur(struct json_tree * tree,struct json_tree_node * node)52 json_tree_set_cur(struct json_tree *tree, struct json_tree_node *node)
53 {
54 	tree->cur = node;
55 	tree->cur_child = tree->cur->value.child;
56 	if (tree->cur_child != NULL) {
57 		while (tree->cur_child->next != NULL)
58 			tree->cur_child = tree->cur_child->next;
59 	}
60 }
61 
62 static int
json_tree_append_value(struct json_tree * tree,enum json_type type,const char * value)63 json_tree_append_value(struct json_tree *tree, enum json_type type,
64 		       const char *value)
65 {
66 	switch (tree->cur->value_type) {
67 	case JSON_TYPE_OBJECT_KEY:
68 		/* "key": value - we already added the node and set its key,
69 		   so now just set the value */
70 		tree->cur->value_type = type;
71 		tree->cur->value.str = p_strdup(tree->pool, value);
72 		json_tree_set_cur(tree, tree->cur->parent);
73 		break;
74 	case JSON_TYPE_ARRAY:
75 		/* element in array - add a new node */
76 		json_tree_append_child(tree, type, value);
77 		break;
78 	default:
79 		return -1;
80 	}
81 	return 0;
82 }
83 
json_tree_append(struct json_tree * tree,enum json_type type,const char * value)84 int json_tree_append(struct json_tree *tree, enum json_type type,
85 		     const char *value)
86 {
87 	switch (type) {
88 	case JSON_TYPE_OBJECT_KEY:
89 		if (tree->cur->value_type != JSON_TYPE_OBJECT)
90 			return -1;
91 		json_tree_append_child(tree, type, NULL);
92 		json_tree_set_cur(tree, tree->cur_child);
93 		tree->cur->key = p_strdup(tree->pool, value);
94 		break;
95 	case JSON_TYPE_ARRAY:
96 		if (json_tree_append_value(tree, type, NULL) < 0)
97 			return -1;
98 		json_tree_set_cur(tree, tree->cur_child);
99 		break;
100 	case JSON_TYPE_OBJECT:
101 		if (tree->cur->value_type == JSON_TYPE_OBJECT_KEY)
102 			tree->cur->value_type = JSON_TYPE_OBJECT;
103 		else if (tree->cur->value_type == JSON_TYPE_ARRAY) {
104 			json_tree_append_child(tree, type, NULL);
105 			json_tree_set_cur(tree, tree->cur_child);
106 		} else {
107 			return -1;
108 		}
109 		break;
110 	case JSON_TYPE_OBJECT_END:
111 		if (tree->cur->parent == NULL ||
112 		    tree->cur->value_type != JSON_TYPE_OBJECT)
113 			return -1;
114 		json_tree_set_cur(tree, tree->cur->parent);
115 		break;
116 	case JSON_TYPE_ARRAY_END:
117 		if (tree->cur->parent == NULL ||
118 		    tree->cur->value_type != JSON_TYPE_ARRAY)
119 			return -1;
120 		json_tree_set_cur(tree, tree->cur->parent);
121 		break;
122 	case JSON_TYPE_STRING:
123 	case JSON_TYPE_NUMBER:
124 	case JSON_TYPE_TRUE:
125 	case JSON_TYPE_FALSE:
126 	case JSON_TYPE_NULL:
127 		if (json_tree_append_value(tree, type, value) < 0)
128 			return -1;
129 		break;
130 	}
131 	return 0;
132 }
133 
134 const struct json_tree_node *
json_tree_root(const struct json_tree * tree)135 json_tree_root(const struct json_tree *tree)
136 {
137 	return tree->root;
138 }
139 
140 const struct json_tree_node *
json_tree_find_key(const struct json_tree_node * node,const char * key)141 json_tree_find_key(const struct json_tree_node *node, const char *key)
142 {
143 	i_assert(node->value_type == JSON_TYPE_OBJECT);
144 
145 	node = json_tree_get_child(node);
146 	for (; node != NULL; node = node->next) {
147 		if (node->key != NULL && strcmp(node->key, key) == 0)
148 			return node;
149 	}
150 	return NULL;
151 }
152 
153 const struct json_tree_node *
json_tree_find_child_with(const struct json_tree_node * node,const char * key,const char * value)154 json_tree_find_child_with(const struct json_tree_node *node,
155 			  const char *key, const char *value)
156 {
157 	const struct json_tree_node *child;
158 
159 	i_assert(node->value_type == JSON_TYPE_OBJECT ||
160 		 node->value_type == JSON_TYPE_ARRAY);
161 
162 	for (node = json_tree_get_child(node); node != NULL; node = node->next) {
163 		if (node->value_type != JSON_TYPE_OBJECT)
164 			continue;
165 
166 		child = json_tree_find_key(node, key);
167 		if (child != NULL &&
168 		    json_tree_get_value_str(child) != NULL &&
169 		    strcmp(json_tree_get_value_str(child), value) == 0)
170 			return node;
171 	}
172 	return NULL;
173 }
174