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