/src/dovecot/src/lib-json/json-tree.c
Line | Count | Source |
1 | | /* Copyright (c) 2017-2023 Dovecot authors, see the included COPYING file */ |
2 | | |
3 | | #include "lib.h" |
4 | | #include "llist.h" |
5 | | #include "array.h" |
6 | | #include "istream.h" |
7 | | |
8 | | #include "json-tree.h" |
9 | | |
10 | | struct json_tree_node_list { |
11 | | struct json_tree_node *head, *tail; |
12 | | unsigned int count; |
13 | | }; |
14 | | |
15 | | struct json_tree_node { |
16 | | struct json_tree *tree; |
17 | | struct json_tree_node *parent, *prev, *next; |
18 | | |
19 | | struct json_node node; |
20 | | }; |
21 | | |
22 | | struct json_tree { |
23 | | struct json_tree_node node; |
24 | | |
25 | | pool_t pool; |
26 | | int refcount; |
27 | | |
28 | | ARRAY_TYPE(json_tree) subtrees; |
29 | | ARRAY(struct istream *) istreams; |
30 | | }; |
31 | | |
32 | | /* |
33 | | * Tree object |
34 | | */ |
35 | | |
36 | | struct json_tree *json_tree_create_pool(pool_t pool) |
37 | 3.26k | { |
38 | 3.26k | struct json_tree *jtree; |
39 | | |
40 | 3.26k | pool_ref(pool); |
41 | | |
42 | 3.26k | jtree = p_new(pool, struct json_tree, 1); |
43 | 3.26k | jtree->refcount = 1; |
44 | 3.26k | jtree->pool = pool; |
45 | | |
46 | 3.26k | jtree->node.tree = jtree; |
47 | 3.26k | jtree->node.node.type = JSON_TYPE_NONE; |
48 | 3.26k | jtree->node.node.value.content_type = JSON_CONTENT_TYPE_NONE; |
49 | | |
50 | 3.26k | return jtree; |
51 | 3.26k | } |
52 | | |
53 | | struct json_tree *json_tree_create(void) |
54 | 3.26k | { |
55 | 3.26k | struct json_tree *jtree; |
56 | 3.26k | pool_t pool; |
57 | | |
58 | 3.26k | pool = pool_alloconly_create("json tree", 1024); |
59 | 3.26k | jtree = json_tree_create_pool(pool); |
60 | 3.26k | pool_unref(&pool); |
61 | | |
62 | 3.26k | return jtree; |
63 | 3.26k | } |
64 | | |
65 | | void json_tree_ref(struct json_tree *jtree) |
66 | 0 | { |
67 | 0 | i_assert(jtree->refcount > 0); |
68 | 0 | jtree->refcount++; |
69 | 0 | } |
70 | | |
71 | | void json_tree_unref(struct json_tree **_jtree) |
72 | 3.26k | { |
73 | 3.26k | struct json_tree *jtree = *_jtree; |
74 | | |
75 | 3.26k | if (jtree == NULL) |
76 | 0 | return; |
77 | 3.26k | *_jtree = NULL; |
78 | | |
79 | 3.26k | i_assert(jtree->refcount > 0); |
80 | 3.26k | if (--jtree->refcount > 0) |
81 | 0 | return; |
82 | | |
83 | 3.26k | if (array_is_created(&jtree->subtrees)) { |
84 | 0 | struct json_tree **subtree_idx; |
85 | 0 | array_foreach_modifiable(&jtree->subtrees, subtree_idx) |
86 | 0 | json_tree_unref(subtree_idx); |
87 | 0 | array_free(&jtree->subtrees); |
88 | 0 | } |
89 | 3.26k | if (array_is_created(&jtree->istreams)) { |
90 | 0 | struct istream **istream_idx; |
91 | 0 | array_foreach_modifiable(&jtree->istreams, istream_idx) |
92 | 0 | i_stream_unref(istream_idx); |
93 | 0 | array_free(&jtree->istreams); |
94 | 0 | } |
95 | 3.26k | pool_unref(&jtree->pool); |
96 | 3.26k | } |
97 | | |
98 | | bool json_tree_is_object(const struct json_tree *jtree) |
99 | 0 | { |
100 | 0 | return json_node_is_object(&jtree->node.node); |
101 | 0 | } |
102 | | |
103 | | bool json_tree_is_array(const struct json_tree *jtree) |
104 | 0 | { |
105 | 0 | return json_node_is_array(&jtree->node.node); |
106 | 0 | } |
107 | | |
108 | | bool json_tree_is_string(const struct json_tree *jtree) |
109 | 0 | { |
110 | 0 | return json_node_is_string(&jtree->node.node); |
111 | 0 | } |
112 | | |
113 | | bool json_tree_is_number(const struct json_tree *jtree) |
114 | 0 | { |
115 | 0 | return json_node_is_number(&jtree->node.node); |
116 | 0 | } |
117 | | |
118 | | bool json_tree_is_true(const struct json_tree *jtree) |
119 | 0 | { |
120 | 0 | return json_node_is_true(&jtree->node.node); |
121 | 0 | } |
122 | | |
123 | | bool json_tree_is_false(const struct json_tree *jtree) |
124 | 0 | { |
125 | 0 | return json_node_is_false(&jtree->node.node); |
126 | 0 | } |
127 | | |
128 | | bool json_tree_is_boolean(const struct json_tree *jtree) |
129 | 0 | { |
130 | 0 | return json_node_is_boolean(&jtree->node.node); |
131 | 0 | } |
132 | | |
133 | | bool json_tree_is_null(const struct json_tree *jtree) |
134 | 0 | { |
135 | 0 | return json_node_is_null(&jtree->node.node); |
136 | 0 | } |
137 | | |
138 | | /* |
139 | | * Tree node |
140 | | */ |
141 | | |
142 | | static inline struct json_tree_node_list * |
143 | | json_tree_node_create_list(struct json_tree_node *jtnode) |
144 | 547k | { |
145 | 547k | i_assert(jtnode->node.type == JSON_TYPE_OBJECT || |
146 | 547k | jtnode->node.type == JSON_TYPE_ARRAY); |
147 | 547k | i_assert(jtnode->node.value.content_type == JSON_CONTENT_TYPE_LIST); |
148 | 547k | if (jtnode->node.value.content.list == NULL) { |
149 | 382k | jtnode->node.value.content.list = |
150 | 382k | p_new(jtnode->tree->pool, |
151 | 382k | struct json_tree_node_list, 1); |
152 | 382k | } |
153 | 547k | return jtnode->node.value.content.list; |
154 | 547k | } |
155 | | |
156 | | struct json_tree_node *json_tree_get_root(struct json_tree *jtree) |
157 | 3.26k | { |
158 | 3.26k | return &jtree->node; |
159 | 3.26k | } |
160 | | |
161 | | const struct json_tree_node * |
162 | | json_tree_get_root_const(const struct json_tree *jtree) |
163 | 0 | { |
164 | 0 | return &jtree->node; |
165 | 0 | } |
166 | | |
167 | | static struct json_tree_node * |
168 | | json_tree_node_create(struct json_tree_node *parent, const char *name) |
169 | 549k | { |
170 | 549k | struct json_tree *jtree = parent->tree; |
171 | 549k | struct json_tree_node_list *list; |
172 | 549k | struct json_tree_node *jtnode; |
173 | | |
174 | 549k | i_assert(name != NULL || parent->node.type != JSON_TYPE_OBJECT); |
175 | | |
176 | 549k | if (parent == &jtree->node && parent->node.type == JSON_TYPE_NONE) { |
177 | | /* We're substituting the root (name is ignored) */ |
178 | 1.73k | i_assert(parent->node.value.content_type == |
179 | 1.73k | JSON_CONTENT_TYPE_NONE); |
180 | 1.73k | jtnode = &jtree->node; |
181 | 1.73k | i_zero(jtnode); |
182 | 547k | } else { |
183 | | /* We're creating a new node */ |
184 | 547k | jtnode = p_new(jtree->pool, struct json_tree_node, 1); |
185 | 547k | jtnode->node.name = (name == NULL ? |
186 | 506k | NULL : p_strdup(jtree->pool, name)); |
187 | 547k | jtnode->parent = parent; |
188 | 547k | list = json_tree_node_create_list(parent); |
189 | 547k | DLLIST2_APPEND(&list->head, &list->tail, jtnode); |
190 | 547k | list->count++; |
191 | 547k | } |
192 | | |
193 | 549k | jtnode->tree = jtree; |
194 | 549k | return jtnode; |
195 | 549k | } |
196 | | |
197 | | /* node */ |
198 | | |
199 | | struct json_tree_node * |
200 | | json_tree_node_add(struct json_tree_node *parent, |
201 | | const struct json_node *jnode) |
202 | 0 | { |
203 | 0 | return json_tree_node_add_value(parent, jnode->name, jnode->type, |
204 | 0 | &jnode->value); |
205 | 0 | } |
206 | | |
207 | | /* object, array */ |
208 | | |
209 | | struct json_tree_node * |
210 | | json_tree_node_add_object(struct json_tree_node *parent, const char *name) |
211 | 2.11k | { |
212 | 2.11k | struct json_tree_node *jtnode; |
213 | | |
214 | 2.11k | jtnode = json_tree_node_create(parent, name); |
215 | 2.11k | jtnode->node.type = JSON_TYPE_OBJECT; |
216 | 2.11k | jtnode->node.value.content_type = JSON_CONTENT_TYPE_LIST; |
217 | 2.11k | jtnode->node.value.content.list = NULL; |
218 | | |
219 | 2.11k | return jtnode; |
220 | 2.11k | } |
221 | | |
222 | | struct json_tree_node * |
223 | | json_tree_node_add_array(struct json_tree_node *parent, const char *name) |
224 | 387k | { |
225 | 387k | struct json_tree_node *jtnode; |
226 | | |
227 | 387k | jtnode = json_tree_node_create(parent, name); |
228 | 387k | jtnode->node.type = JSON_TYPE_ARRAY; |
229 | 387k | jtnode->node.value.content_type = JSON_CONTENT_TYPE_LIST; |
230 | 387k | jtnode->node.value.content.list = NULL; |
231 | | |
232 | 387k | return jtnode; |
233 | 387k | } |
234 | | |
235 | | /* value */ |
236 | | |
237 | | struct json_tree_node * |
238 | | json_tree_node_add_value(struct json_tree_node *parent, const char *name, |
239 | | enum json_type type, const struct json_value *jvalue) |
240 | 159k | { |
241 | 159k | struct json_tree *jtree = parent->tree; |
242 | 159k | struct json_tree_node *jtnode; |
243 | 159k | struct json_data *jdata; |
244 | 159k | unsigned char *data; |
245 | | |
246 | 159k | jtnode = json_tree_node_create(parent, name); |
247 | 159k | jtnode->node.type = type; |
248 | 159k | jtnode->node.value.content_type = jvalue->content_type; |
249 | 159k | switch (jvalue->content_type) { |
250 | 1.48k | case JSON_CONTENT_TYPE_NONE: |
251 | 1.48k | break; |
252 | 0 | case JSON_CONTENT_TYPE_LIST: |
253 | | /* Equivalent to calling json_tree_node_add_array() or |
254 | | json_tree_node_add_object(); doesn't copy list */ |
255 | 0 | jtnode->node.value.content.list = NULL; |
256 | 0 | break; |
257 | 3.93k | case JSON_CONTENT_TYPE_STRING: |
258 | 3.93k | jtnode->node.value.content.str = |
259 | 3.93k | p_strdup(jtree->pool, jvalue->content.str); |
260 | 3.93k | break; |
261 | 0 | case JSON_CONTENT_TYPE_DATA: |
262 | 0 | jdata = p_new(jtree->pool, struct json_data, 1); |
263 | 0 | *jdata = *jvalue->content.data; |
264 | 0 | data = p_malloc(jtree->pool, jdata->size + 1); |
265 | 0 | jdata->data = memcpy(data, jdata->data, jdata->size); |
266 | 0 | jtnode->node.value.content.data = jdata; |
267 | 0 | break; |
268 | 0 | case JSON_CONTENT_TYPE_STREAM: |
269 | 0 | if (!array_is_created(&jtree->istreams)) |
270 | 0 | i_array_init(&jtree->istreams, 4); |
271 | 0 | array_append(&jtree->istreams, &jvalue->content.stream, 1); |
272 | 0 | jtnode->node.value.content.stream = jvalue->content.stream; |
273 | 0 | i_stream_ref(jvalue->content.stream); |
274 | 0 | break; |
275 | 154k | case JSON_CONTENT_TYPE_INTEGER: |
276 | 154k | jtnode->node.value.content.intnum = jvalue->content.intnum; |
277 | 154k | break; |
278 | 0 | case JSON_CONTENT_TYPE_TREE: |
279 | 0 | i_assert(jvalue->content.tree != jtree); |
280 | 0 | if (!array_is_created(&jtree->subtrees)) |
281 | 0 | i_array_init(&jtree->subtrees, 4); |
282 | 0 | array_append(&jtree->subtrees, &jvalue->content.tree, 1); |
283 | 0 | jtnode->node.value.content.tree = jvalue->content.tree; |
284 | 0 | json_tree_ref(jvalue->content.tree); |
285 | 0 | break; |
286 | 159k | } |
287 | | |
288 | 159k | return jtnode; |
289 | 159k | } |
290 | | |
291 | | /* string */ |
292 | | |
293 | | struct json_tree_node * |
294 | | json_tree_node_add_string(struct json_tree_node *parent, const char *name, |
295 | | const char *str) |
296 | 0 | { |
297 | 0 | struct json_value jvalue; |
298 | |
|
299 | 0 | i_zero(&jvalue); |
300 | 0 | jvalue.content_type = JSON_CONTENT_TYPE_STRING; |
301 | 0 | jvalue.content.str = str; |
302 | 0 | return json_tree_node_add_value(parent, name, JSON_TYPE_STRING, |
303 | 0 | &jvalue); |
304 | 0 | } |
305 | | |
306 | | struct json_tree_node * |
307 | | json_tree_node_add_data(struct json_tree_node *parent, const char *name, |
308 | | const unsigned char *data, size_t size) |
309 | 0 | { |
310 | 0 | struct json_value jvalue; |
311 | 0 | struct json_data jdata; |
312 | |
|
313 | 0 | i_zero(&data); |
314 | 0 | jdata.data = data; |
315 | 0 | jdata.size = size; |
316 | |
|
317 | 0 | i_zero(&jvalue); |
318 | 0 | jvalue.content_type = JSON_CONTENT_TYPE_DATA; |
319 | 0 | jvalue.content.data = &jdata; |
320 | 0 | return json_tree_node_add_value(parent, name, JSON_TYPE_STRING, |
321 | 0 | &jvalue); |
322 | 0 | } |
323 | | |
324 | | struct json_tree_node * |
325 | | json_tree_node_add_string_stream(struct json_tree_node *parent, |
326 | | const char *name, struct istream *input) |
327 | 0 | { |
328 | 0 | struct json_value jvalue; |
329 | |
|
330 | 0 | i_zero(&jvalue); |
331 | 0 | jvalue.content_type = JSON_CONTENT_TYPE_STREAM; |
332 | 0 | jvalue.content.stream = input; |
333 | 0 | return json_tree_node_add_value(parent, name, JSON_TYPE_STRING, |
334 | 0 | &jvalue); |
335 | 0 | } |
336 | | |
337 | | /* number */ |
338 | | |
339 | | struct json_tree_node * |
340 | | json_tree_node_add_number_int(struct json_tree_node *parent, const char *name, |
341 | | uintmax_t num) |
342 | 0 | { |
343 | 0 | struct json_value jvalue; |
344 | |
|
345 | 0 | i_zero(&jvalue); |
346 | 0 | jvalue.content_type = JSON_CONTENT_TYPE_INTEGER; |
347 | 0 | jvalue.content.intnum = num; |
348 | 0 | return json_tree_node_add_value(parent, name, JSON_TYPE_NUMBER, |
349 | 0 | &jvalue); |
350 | 0 | } |
351 | | |
352 | | struct json_tree_node * |
353 | | json_tree_node_add_number_str(struct json_tree_node *parent, const char *name, |
354 | | const char *num) |
355 | 0 | { |
356 | 0 | struct json_value jvalue; |
357 | |
|
358 | 0 | i_zero(&jvalue); |
359 | 0 | jvalue.content_type = JSON_CONTENT_TYPE_STRING; |
360 | 0 | jvalue.content.str = num; |
361 | 0 | return json_tree_node_add_value(parent, name, JSON_TYPE_NUMBER, |
362 | 0 | &jvalue); |
363 | 0 | } |
364 | | |
365 | | /* false, true */ |
366 | | |
367 | | struct json_tree_node * |
368 | | json_tree_node_add_false(struct json_tree_node *parent, const char *name) |
369 | 0 | { |
370 | 0 | struct json_value jvalue; |
371 | |
|
372 | 0 | i_zero(&jvalue); |
373 | 0 | return json_tree_node_add_value(parent, name, JSON_TYPE_FALSE, |
374 | 0 | &jvalue); |
375 | 0 | } |
376 | | |
377 | | struct json_tree_node * |
378 | | json_tree_node_add_true(struct json_tree_node *parent, const char *name) |
379 | 0 | { |
380 | 0 | struct json_value jvalue; |
381 | |
|
382 | 0 | i_zero(&jvalue); |
383 | 0 | return json_tree_node_add_value(parent, name, JSON_TYPE_TRUE, |
384 | 0 | &jvalue); |
385 | 0 | } |
386 | | |
387 | | struct json_tree_node * |
388 | | json_tree_node_add_boolean(struct json_tree_node *parent, const char *name, |
389 | | bool val) |
390 | 0 | { |
391 | 0 | struct json_value jvalue; |
392 | |
|
393 | 0 | i_zero(&jvalue); |
394 | 0 | return json_tree_node_add_value( |
395 | 0 | parent, name, (val ? JSON_TYPE_TRUE : JSON_TYPE_FALSE), |
396 | 0 | &jvalue); |
397 | 0 | } |
398 | | |
399 | | /* null */ |
400 | | |
401 | | struct json_tree_node * |
402 | | json_tree_node_add_null(struct json_tree_node *parent, const char *name) |
403 | 0 | { |
404 | 0 | struct json_value jvalue; |
405 | |
|
406 | 0 | i_zero(&jvalue); |
407 | 0 | return json_tree_node_add_value(parent, name, JSON_TYPE_NULL, |
408 | 0 | &jvalue); |
409 | 0 | } |
410 | | |
411 | | /* JSON-text */ |
412 | | |
413 | | struct json_tree_node * |
414 | | json_tree_node_add_text(struct json_tree_node *parent, const char *name, |
415 | | const char *literal) |
416 | 0 | { |
417 | 0 | struct json_value jvalue; |
418 | |
|
419 | 0 | i_zero(&jvalue); |
420 | 0 | jvalue.content_type = JSON_CONTENT_TYPE_STRING; |
421 | 0 | jvalue.content.str = literal; |
422 | 0 | return json_tree_node_add_value(parent, name, JSON_TYPE_TEXT, &jvalue); |
423 | 0 | } |
424 | | |
425 | | struct json_tree_node * |
426 | | json_tree_node_add_text_data(struct json_tree_node *parent, const char *name, |
427 | | const unsigned char *data, size_t size) |
428 | 0 | { |
429 | 0 | struct json_value jvalue; |
430 | 0 | struct json_data jdata; |
431 | |
|
432 | 0 | i_zero(&jdata); |
433 | 0 | jdata.data = data; |
434 | 0 | jdata.size = size; |
435 | |
|
436 | 0 | i_zero(&jvalue); |
437 | 0 | jvalue.content_type = JSON_CONTENT_TYPE_DATA; |
438 | 0 | jvalue.content.data = &jdata; |
439 | 0 | return json_tree_node_add_value(parent, name, JSON_TYPE_TEXT, &jvalue); |
440 | 0 | } |
441 | | |
442 | | struct json_tree_node * |
443 | | json_tree_node_add_subtree(struct json_tree_node *parent, const char *name, |
444 | | struct json_tree *tree) |
445 | 0 | { |
446 | 0 | struct json_value jvalue; |
447 | |
|
448 | 0 | i_zero(&jvalue); |
449 | 0 | jvalue.content_type = JSON_CONTENT_TYPE_TREE; |
450 | 0 | jvalue.content.tree = tree; |
451 | 0 | return json_tree_node_add_value(parent, name, JSON_TYPE_TEXT, &jvalue); |
452 | 0 | } |
453 | | |
454 | | /* |
455 | | * Tree inspection |
456 | | */ |
457 | | |
458 | | enum json_type json_tree_node_get_type(const struct json_tree_node *jtnode) |
459 | 0 | { |
460 | 0 | return jtnode->node.type; |
461 | 0 | } |
462 | | |
463 | | const char *json_tree_node_get_name(const struct json_tree_node *jtnode) |
464 | 0 | { |
465 | 0 | return jtnode->node.name; |
466 | 0 | } |
467 | | |
468 | | struct json_tree * |
469 | | json_tree_node_get_tree(struct json_tree_node *jtnode) |
470 | 0 | { |
471 | 0 | return jtnode->tree; |
472 | 0 | } |
473 | | |
474 | | const struct json_tree * |
475 | | json_tree_node_get_tree_const(const struct json_tree_node *jtnode) |
476 | 0 | { |
477 | 0 | return jtnode->tree; |
478 | 0 | } |
479 | | |
480 | | bool json_tree_node_is_root(const struct json_tree_node *jtnode) |
481 | 0 | { |
482 | 0 | return (json_tree_get_root(jtnode->tree) == jtnode); |
483 | 0 | } |
484 | | |
485 | | bool json_tree_node_is_object(const struct json_tree_node *jtnode) |
486 | 0 | { |
487 | 0 | return json_node_is_object(&jtnode->node); |
488 | 0 | } |
489 | | |
490 | | bool json_tree_node_is_array(const struct json_tree_node *jtnode) |
491 | 0 | { |
492 | 0 | return json_node_is_array(&jtnode->node); |
493 | 0 | } |
494 | | |
495 | | bool json_tree_node_is_string(const struct json_tree_node *jtnode) |
496 | 0 | { |
497 | 0 | return json_node_is_string(&jtnode->node); |
498 | 0 | } |
499 | | |
500 | | bool json_tree_node_is_number(const struct json_tree_node *jtnode) |
501 | 0 | { |
502 | 0 | return json_node_is_number(&jtnode->node); |
503 | 0 | } |
504 | | |
505 | | bool json_tree_node_is_true(const struct json_tree_node *jtnode) |
506 | 0 | { |
507 | 0 | return json_node_is_true(&jtnode->node); |
508 | 0 | } |
509 | | |
510 | | bool json_tree_node_is_false(const struct json_tree_node *jtnode) |
511 | 0 | { |
512 | 0 | return json_node_is_false(&jtnode->node); |
513 | 0 | } |
514 | | |
515 | | bool json_tree_node_is_boolean(const struct json_tree_node *jtnode) |
516 | 0 | { |
517 | 0 | return json_node_is_boolean(&jtnode->node); |
518 | 0 | } |
519 | | |
520 | | bool json_tree_node_is_null(const struct json_tree_node *jtnode) |
521 | 0 | { |
522 | 0 | return json_node_is_null(&jtnode->node); |
523 | 0 | } |
524 | | |
525 | | const struct json_node * |
526 | | json_tree_node_get(const struct json_tree_node *jtnode) |
527 | 0 | { |
528 | 0 | return &jtnode->node; |
529 | 0 | } |
530 | | |
531 | | struct json_tree_node * |
532 | | json_tree_node_get_next(const struct json_tree_node *jtnode) |
533 | 0 | { |
534 | 0 | return jtnode->next; |
535 | 0 | } |
536 | | |
537 | | struct json_tree_node * |
538 | | json_tree_node_get_parent(const struct json_tree_node *jtnode) |
539 | 0 | { |
540 | 0 | return jtnode->parent; |
541 | 0 | } |
542 | | |
543 | | struct json_tree_node * |
544 | | json_tree_node_get_child(const struct json_tree_node *jtnode) |
545 | 0 | { |
546 | 0 | i_assert(jtnode->node.value.content_type == JSON_CONTENT_TYPE_LIST); |
547 | 0 | if (jtnode->node.value.content.list == NULL) |
548 | 0 | return NULL; |
549 | 0 | return jtnode->node.value.content.list->head; |
550 | 0 | } |
551 | | |
552 | | unsigned int |
553 | | json_tree_node_get_child_count(const struct json_tree_node *jtnode) |
554 | 0 | { |
555 | 0 | i_assert(jtnode->node.value.content_type == JSON_CONTENT_TYPE_LIST); |
556 | 0 | if (jtnode->node.value.content.list == NULL) |
557 | 0 | return 0; |
558 | 0 | return jtnode->node.value.content.list->count; |
559 | 0 | } |
560 | | |
561 | | struct json_tree_node * |
562 | | json_tree_node_get_member(const struct json_tree_node *jtnode, |
563 | | const char *name) |
564 | 0 | { |
565 | 0 | struct json_tree_node *child; |
566 | |
|
567 | 0 | i_assert(json_node_is_object(&jtnode->node)); |
568 | 0 | i_assert(jtnode->node.value.content_type == JSON_CONTENT_TYPE_LIST); |
569 | | |
570 | 0 | if (jtnode->node.value.content.list == NULL) |
571 | 0 | return NULL; |
572 | | |
573 | 0 | child = jtnode->node.value.content.list->head; |
574 | 0 | while (child != NULL) { |
575 | 0 | if (strcmp(child->node.name, name) == 0) |
576 | 0 | return child; |
577 | 0 | child = child->next; |
578 | 0 | } |
579 | 0 | return NULL; |
580 | 0 | } |
581 | | |
582 | | struct json_tree_node * |
583 | | json_tree_node_get_child_with(const struct json_tree_node *jtnode, |
584 | | const char *key, const char *value) |
585 | 0 | { |
586 | 0 | struct json_tree_node *child; |
587 | |
|
588 | 0 | i_assert(jtnode->node.value.content_type == JSON_CONTENT_TYPE_LIST); |
589 | 0 | if (jtnode->node.value.content.list == NULL) |
590 | 0 | return NULL; |
591 | | |
592 | 0 | child = jtnode->node.value.content.list->head; |
593 | 0 | while (child != NULL) { |
594 | 0 | struct json_tree_node *member; |
595 | |
|
596 | 0 | if (!json_node_is_object(&child->node)) |
597 | 0 | continue; |
598 | 0 | member = json_tree_node_get_member(child, key); |
599 | 0 | if (member == NULL) |
600 | 0 | continue; |
601 | 0 | if (!json_tree_node_is_string(member)) |
602 | 0 | continue; |
603 | 0 | if (strcmp(json_tree_node_get_str(member), value) == 0) |
604 | 0 | break; |
605 | | |
606 | 0 | child = child->next; |
607 | 0 | } |
608 | |
|
609 | 0 | return child; |
610 | 0 | } |
611 | | |
612 | | /* |
613 | | * Walker |
614 | | */ |
615 | | |
616 | | struct json_tree_walker { |
617 | | const struct json_tree_node *root, *node; |
618 | | ARRAY_TYPE(json_tree_node_const) sub_nodes; |
619 | | unsigned int node_level; |
620 | | |
621 | | bool node_is_end:1; |
622 | | }; |
623 | | |
624 | | struct json_tree_walker * |
625 | | json_tree_walker_create_from_node(const struct json_tree_node *tree_node) |
626 | 0 | { |
627 | 0 | struct json_tree_walker *twalker; |
628 | |
|
629 | 0 | i_assert(tree_node != NULL); |
630 | | |
631 | 0 | twalker = i_new(struct json_tree_walker, 1); |
632 | 0 | twalker->root = tree_node; |
633 | |
|
634 | 0 | return twalker; |
635 | 0 | } |
636 | | |
637 | | struct json_tree_walker * |
638 | | json_tree_walker_create(const struct json_tree *tree) |
639 | 0 | { |
640 | 0 | i_assert(tree != NULL); |
641 | 0 | return json_tree_walker_create_from_node( |
642 | 0 | json_tree_get_root_const(tree)); |
643 | 0 | } |
644 | | |
645 | | void json_tree_walker_free(struct json_tree_walker **_twalker) |
646 | 0 | { |
647 | 0 | struct json_tree_walker *twalker = *_twalker; |
648 | |
|
649 | 0 | if (twalker == NULL) |
650 | 0 | return; |
651 | 0 | *_twalker = NULL; |
652 | |
|
653 | 0 | array_free(&twalker->sub_nodes); |
654 | 0 | i_free(twalker); |
655 | 0 | } |
656 | | |
657 | | static const struct json_tree_node * |
658 | | json_tree_walk_next(struct json_tree_walker *twalker, bool *is_end_r) |
659 | 0 | { |
660 | 0 | const struct json_tree_node *tnode = twalker->node, *tnode_next; |
661 | |
|
662 | 0 | *is_end_r = FALSE; |
663 | |
|
664 | 0 | if (tnode == NULL) { |
665 | 0 | i_assert(twalker->node_level == 0); |
666 | 0 | twalker->node_level++; |
667 | 0 | return twalker->root; |
668 | 0 | } |
669 | | |
670 | 0 | bool tnode_is_end = twalker->node_is_end; |
671 | 0 | const struct json_node *node = &tnode->node; |
672 | |
|
673 | 0 | if (!json_node_is_singular(node) && !tnode_is_end) { |
674 | 0 | tnode_next = json_tree_node_get_child(tnode); |
675 | 0 | if (tnode_next != NULL) { |
676 | 0 | twalker->node_level++; |
677 | 0 | return tnode_next; |
678 | 0 | } |
679 | 0 | *is_end_r = TRUE; |
680 | 0 | return tnode; |
681 | 0 | } |
682 | | |
683 | 0 | tnode_next = json_tree_node_get_next(tnode); |
684 | 0 | if (tnode_next != NULL || twalker->node_level == 0) |
685 | 0 | return tnode_next; |
686 | | |
687 | 0 | twalker->node_level--; |
688 | 0 | *is_end_r = TRUE; |
689 | 0 | return json_tree_node_get_parent(tnode); |
690 | 0 | } |
691 | | |
692 | | bool json_tree_walk(struct json_tree_walker *twalker, struct json_node *node_r) |
693 | 0 | { |
694 | 0 | const struct json_tree_node *tnode_next; |
695 | 0 | bool tnode_next_is_end; |
696 | |
|
697 | 0 | tnode_next = json_tree_walk_next(twalker, &tnode_next_is_end); |
698 | 0 | if (tnode_next == NULL) { |
699 | 0 | i_assert(twalker->node_level == 0); |
700 | 0 | i_zero(node_r); |
701 | 0 | twalker->node = twalker->root = NULL; |
702 | 0 | twalker->node_is_end = TRUE; |
703 | 0 | return FALSE; |
704 | 0 | } |
705 | 0 | if (json_tree_node_is_root(tnode_next) && twalker->node_level > 1) { |
706 | 0 | const struct json_tree_node *tnode_sub = tnode_next; |
707 | | |
708 | | /* Returned to root of subtree */ |
709 | 0 | i_assert(tnode_next_is_end); |
710 | 0 | i_assert(array_is_created(&twalker->sub_nodes)); |
711 | 0 | i_assert(array_count(&twalker->sub_nodes) > 0); |
712 | 0 | tnode_next = *array_back(&twalker->sub_nodes); |
713 | 0 | array_pop_back(&twalker->sub_nodes); |
714 | |
|
715 | 0 | i_zero(node_r); |
716 | 0 | node_r->name = tnode_next->node.name; |
717 | 0 | node_r->type = tnode_sub->node.type; |
718 | |
|
719 | 0 | twalker->node = tnode_next; |
720 | 0 | twalker->node_is_end = TRUE; |
721 | 0 | return TRUE; |
722 | 0 | } |
723 | | |
724 | 0 | const struct json_node *node_next = &tnode_next->node; |
725 | |
|
726 | 0 | if (tnode_next_is_end) { |
727 | 0 | i_zero(node_r); |
728 | 0 | node_r->name = node_next->name; |
729 | 0 | node_r->type = node_next->type; |
730 | 0 | } else if (node_next->type == JSON_TYPE_TEXT && |
731 | 0 | node_next->value.content_type == JSON_CONTENT_TYPE_TREE) { |
732 | 0 | struct json_tree *tree = node_next->value.content.tree; |
733 | 0 | const struct json_tree_node *tnode_sub; |
734 | | |
735 | | /* Descend into subtree */ |
736 | 0 | if (!array_is_created(&twalker->sub_nodes)) |
737 | 0 | i_array_init(&twalker->sub_nodes, 4); |
738 | 0 | array_push_back(&twalker->sub_nodes, &tnode_next); |
739 | 0 | tnode_sub = json_tree_get_root(tree); |
740 | 0 | i_assert(tnode_sub != NULL); |
741 | 0 | i_assert(tnode_sub->node.type != JSON_TYPE_NONE); |
742 | 0 | *node_r = tnode_sub->node; |
743 | 0 | node_r->name = node_next->name; |
744 | 0 | tnode_next = tnode_sub; |
745 | 0 | } else { |
746 | 0 | *node_r = tnode_next->node; |
747 | 0 | } |
748 | | |
749 | 0 | twalker->node = tnode_next; |
750 | 0 | twalker->node_is_end = tnode_next_is_end; |
751 | 0 | return TRUE; |
752 | 0 | } |