diff options
Diffstat (limited to 'src/jplist.c')
| -rw-r--r-- | src/jplist.c | 23 |
1 files changed, 21 insertions, 2 deletions
diff --git a/src/jplist.c b/src/jplist.c index 1c7a932..2e53400 100644 --- a/src/jplist.c +++ b/src/jplist.c | |||
| @@ -38,6 +38,7 @@ | |||
| 38 | #include "plist.h" | 38 | #include "plist.h" |
| 39 | #include "strbuf.h" | 39 | #include "strbuf.h" |
| 40 | #include "jsmn.h" | 40 | #include "jsmn.h" |
| 41 | #include "hashtable.h" | ||
| 41 | 42 | ||
| 42 | #ifdef DEBUG | 43 | #ifdef DEBUG |
| 43 | static int plist_json_debug = 0; | 44 | static int plist_json_debug = 0; |
| @@ -315,18 +316,27 @@ static int num_digits_u(uint64_t i) | |||
| 315 | return n; | 316 | return n; |
| 316 | } | 317 | } |
| 317 | 318 | ||
| 318 | static plist_err_t node_estimate_size(node_t node, uint64_t *size, uint32_t depth, int prettify) | 319 | static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t depth, int prettify, hashtable_t *visited) |
| 319 | { | 320 | { |
| 320 | plist_data_t data; | 321 | plist_data_t data; |
| 321 | if (!node) { | 322 | if (!node) { |
| 322 | return PLIST_ERR_INVALID_ARG; | 323 | return PLIST_ERR_INVALID_ARG; |
| 323 | } | 324 | } |
| 325 | |||
| 326 | if (hash_table_lookup(visited, node)) { | ||
| 327 | PLIST_JSON_WRITE_ERR("circular reference detected\n"); | ||
| 328 | return PLIST_ERR_CIRCULAR_REF; | ||
| 329 | } | ||
| 330 | |||
| 331 | // mark as visited | ||
| 332 | hash_table_insert(visited, node, (void*)1); | ||
| 333 | |||
| 324 | data = plist_get_data(node); | 334 | data = plist_get_data(node); |
| 325 | if (node->children) { | 335 | if (node->children) { |
| 326 | node_t ch; | 336 | node_t ch; |
| 327 | unsigned int n_children = node_n_children(node); | 337 | unsigned int n_children = node_n_children(node); |
| 328 | for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) { | 338 | for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) { |
| 329 | plist_err_t res = node_estimate_size(ch, size, depth + 1, prettify); | 339 | plist_err_t res = _node_estimate_size(ch, size, depth + 1, prettify, visited); |
| 330 | if (res < 0) { | 340 | if (res < 0) { |
| 331 | return res; | 341 | return res; |
| 332 | } | 342 | } |
| @@ -402,6 +412,15 @@ static plist_err_t node_estimate_size(node_t node, uint64_t *size, uint32_t dept | |||
| 402 | return PLIST_ERR_SUCCESS; | 412 | return PLIST_ERR_SUCCESS; |
| 403 | } | 413 | } |
| 404 | 414 | ||
| 415 | static plist_err_t node_estimate_size(node_t node, uint64_t *size, uint32_t depth, int prettify) | ||
| 416 | { | ||
| 417 | hashtable_t *visited = hash_table_new(plist_node_ptr_hash, plist_node_ptr_compare, NULL); | ||
| 418 | if (!visited) return PLIST_ERR_NO_MEM; | ||
| 419 | plist_err_t err = _node_estimate_size(node, size, depth, prettify, visited); | ||
| 420 | hash_table_destroy(visited); | ||
| 421 | return err; | ||
| 422 | } | ||
| 423 | |||
| 405 | plist_err_t plist_to_json(plist_t plist, char **plist_json, uint32_t* length, int prettify) | 424 | plist_err_t plist_to_json(plist_t plist, char **plist_json, uint32_t* length, int prettify) |
| 406 | { | 425 | { |
| 407 | uint64_t size = 0; | 426 | uint64_t size = 0; |
