diff options
Diffstat (limited to 'src/out-default.c')
| -rw-r--r-- | src/out-default.c | 27 |
1 files changed, 24 insertions, 3 deletions
diff --git a/src/out-default.c b/src/out-default.c index 266070b..09e64c3 100644 --- a/src/out-default.c +++ b/src/out-default.c | |||
| @@ -38,6 +38,7 @@ | |||
| 38 | #include "plist.h" | 38 | #include "plist.h" |
| 39 | #include "strbuf.h" | 39 | #include "strbuf.h" |
| 40 | #include "time64.h" | 40 | #include "time64.h" |
| 41 | #include "hashtable.h" | ||
| 41 | 42 | ||
| 42 | #define MAC_EPOCH 978307200 | 43 | #define MAC_EPOCH 978307200 |
| 43 | 44 | ||
| @@ -310,19 +311,30 @@ static int num_digits_u(uint64_t i) | |||
| 310 | return n; | 311 | return n; |
| 311 | } | 312 | } |
| 312 | 313 | ||
| 313 | static plist_err_t node_estimate_size(node_t node, uint64_t *size, uint32_t depth, uint32_t indent, int partial_data) | 314 | static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t depth, uint32_t indent, int partial_data, hashtable_t *visited) |
| 314 | { | 315 | { |
| 315 | plist_data_t data; | 316 | plist_data_t data; |
| 316 | if (!node) { | 317 | if (!node) { |
| 317 | return PLIST_ERR_INVALID_ARG; | 318 | return PLIST_ERR_INVALID_ARG; |
| 318 | } | 319 | } |
| 320 | |||
| 321 | if (hash_table_lookup(visited, node)) { | ||
| 322 | #if DEBUG | ||
| 323 | fprintf(stderr, "libplist: ERROR: circular reference detected\n"); | ||
| 324 | #endif | ||
| 325 | return PLIST_ERR_CIRCULAR_REF; | ||
| 326 | } | ||
| 327 | |||
| 328 | // mark as visited | ||
| 329 | hash_table_insert(visited, node, (void*)1); | ||
| 330 | |||
| 319 | data = plist_get_data(node); | 331 | data = plist_get_data(node); |
| 320 | if (node->children) { | 332 | if (node->children) { |
| 321 | node_t ch; | 333 | node_t ch; |
| 322 | unsigned int n_children = node_n_children(node); | 334 | unsigned int n_children = node_n_children(node); |
| 323 | for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) { | 335 | for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) { |
| 324 | plist_err_t res = node_estimate_size(ch, size, depth + 1, indent, partial_data); | 336 | plist_err_t res = _node_estimate_size(ch, size, depth + 1, indent, partial_data, visited); |
| 325 | if (res < 0) { | 337 | if (res != PLIST_ERR_SUCCESS) { |
| 326 | return res; | 338 | return res; |
| 327 | } | 339 | } |
| 328 | } | 340 | } |
| @@ -401,6 +413,15 @@ static plist_err_t node_estimate_size(node_t node, uint64_t *size, uint32_t dept | |||
| 401 | return PLIST_ERR_SUCCESS; | 413 | return PLIST_ERR_SUCCESS; |
| 402 | } | 414 | } |
| 403 | 415 | ||
| 416 | static plist_err_t node_estimate_size(node_t node, uint64_t *size, uint32_t depth, uint32_t indent, int partial_data) | ||
| 417 | { | ||
| 418 | hashtable_t *visited = hash_table_new(plist_node_ptr_hash, plist_node_ptr_compare, NULL); | ||
| 419 | if (!visited) return PLIST_ERR_NO_MEM; | ||
| 420 | plist_err_t err = _node_estimate_size(node, size, depth, indent, partial_data, visited); | ||
| 421 | hash_table_destroy(visited); | ||
| 422 | return err; | ||
| 423 | } | ||
| 424 | |||
| 404 | static plist_err_t _plist_write_to_strbuf(plist_t plist, strbuf_t *outbuf, plist_write_options_t options) | 425 | static plist_err_t _plist_write_to_strbuf(plist_t plist, strbuf_t *outbuf, plist_write_options_t options) |
| 405 | { | 426 | { |
| 406 | uint8_t indent = 0; | 427 | uint8_t indent = 0; |
