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 @@ #include "plist.h" #include "strbuf.h" #include "time64.h" +#include "hashtable.h" #define MAC_EPOCH 978307200 @@ -304,19 +305,30 @@ static int num_digits_u(uint64_t i) return n; } -static plist_err_t node_estimate_size(node_t node, uint64_t *size, uint32_t depth) +static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t depth, hashtable_t *visited) { plist_data_t data; if (!node) { return PLIST_ERR_INVALID_ARG; } + + if (hash_table_lookup(visited, node)) { +#if DEBUG + fprintf(stderr, "libplist: ERROR: circular reference detected\n"); +#endif + return PLIST_ERR_CIRCULAR_REF; + } + + // mark as visited + hash_table_insert(visited, node, (void*)1); + data = plist_get_data(node); if (node->children) { node_t ch; unsigned int n_children = node_n_children(node); for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) { - plist_err_t res = node_estimate_size(ch, size, depth + 1); - if (res < 0) { + plist_err_t res = _node_estimate_size(ch, size, depth + 1, visited); + if (res != PLIST_ERR_SUCCESS) { return res; } } @@ -388,6 +400,15 @@ static plist_err_t node_estimate_size(node_t node, uint64_t *size, uint32_t dept return PLIST_ERR_SUCCESS; } +static plist_err_t node_estimate_size(node_t node, uint64_t *size, uint32_t depth) +{ + hashtable_t *visited = hash_table_new(plist_node_ptr_hash, plist_node_ptr_compare, NULL); + if (!visited) return PLIST_ERR_NO_MEM; + plist_err_t err = _node_estimate_size(node, size, depth, visited); + hash_table_destroy(visited); + return err; +} + static plist_err_t _plist_write_to_strbuf(plist_t plist, strbuf_t *outbuf, plist_write_options_t options) { plist_err_t res = node_to_string((node_t)plist, &outbuf, 0); |
