diff options
Diffstat (limited to 'src/out-plutil.c')
| -rw-r--r-- | src/out-plutil.c | 27 |
1 files changed, 24 insertions, 3 deletions
diff --git a/src/out-plutil.c b/src/out-plutil.c index d85f22c..5354aa3 100644 --- a/src/out-plutil.c +++ b/src/out-plutil.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 | ||
| @@ -304,19 +305,30 @@ static int num_digits_u(uint64_t i) | |||
| 304 | return n; | 305 | return n; |
| 305 | } | 306 | } |
| 306 | 307 | ||
| 307 | static plist_err_t node_estimate_size(node_t node, uint64_t *size, uint32_t depth) | 308 | static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t depth, hashtable_t *visited) |
| 308 | { | 309 | { |
| 309 | plist_data_t data; | 310 | plist_data_t data; |
| 310 | if (!node) { | 311 | if (!node) { |
| 311 | return PLIST_ERR_INVALID_ARG; | 312 | return PLIST_ERR_INVALID_ARG; |
| 312 | } | 313 | } |
| 314 | |||
| 315 | if (hash_table_lookup(visited, node)) { | ||
| 316 | #if DEBUG | ||
| 317 | fprintf(stderr, "libplist: ERROR: circular reference detected\n"); | ||
| 318 | #endif | ||
| 319 | return PLIST_ERR_CIRCULAR_REF; | ||
| 320 | } | ||
| 321 | |||
| 322 | // mark as visited | ||
| 323 | hash_table_insert(visited, node, (void*)1); | ||
| 324 | |||
| 313 | data = plist_get_data(node); | 325 | data = plist_get_data(node); |
| 314 | if (node->children) { | 326 | if (node->children) { |
| 315 | node_t ch; | 327 | node_t ch; |
| 316 | unsigned int n_children = node_n_children(node); | 328 | unsigned int n_children = node_n_children(node); |
| 317 | for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) { | 329 | for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) { |
| 318 | plist_err_t res = node_estimate_size(ch, size, depth + 1); | 330 | plist_err_t res = _node_estimate_size(ch, size, depth + 1, visited); |
| 319 | if (res < 0) { | 331 | if (res != PLIST_ERR_SUCCESS) { |
| 320 | return res; | 332 | return res; |
| 321 | } | 333 | } |
| 322 | } | 334 | } |
| @@ -388,6 +400,15 @@ static plist_err_t node_estimate_size(node_t node, uint64_t *size, uint32_t dept | |||
| 388 | return PLIST_ERR_SUCCESS; | 400 | return PLIST_ERR_SUCCESS; |
| 389 | } | 401 | } |
| 390 | 402 | ||
| 403 | static plist_err_t node_estimate_size(node_t node, uint64_t *size, uint32_t depth) | ||
| 404 | { | ||
| 405 | hashtable_t *visited = hash_table_new(plist_node_ptr_hash, plist_node_ptr_compare, NULL); | ||
| 406 | if (!visited) return PLIST_ERR_NO_MEM; | ||
| 407 | plist_err_t err = _node_estimate_size(node, size, depth, visited); | ||
| 408 | hash_table_destroy(visited); | ||
| 409 | return err; | ||
| 410 | } | ||
| 411 | |||
| 391 | static plist_err_t _plist_write_to_strbuf(plist_t plist, strbuf_t *outbuf, plist_write_options_t options) | 412 | static plist_err_t _plist_write_to_strbuf(plist_t plist, strbuf_t *outbuf, plist_write_options_t options) |
| 392 | { | 413 | { |
| 393 | plist_err_t res = node_to_string((node_t)plist, &outbuf, 0); | 414 | plist_err_t res = node_to_string((node_t)plist, &outbuf, 0); |
