diff options
Diffstat (limited to 'src/bplist.c')
| -rw-r--r-- | src/bplist.c | 64 |
1 files changed, 51 insertions, 13 deletions
diff --git a/src/bplist.c b/src/bplist.c index b2d0e7c..ca2a556 100644 --- a/src/bplist.c +++ b/src/bplist.c | |||
| @@ -244,8 +244,10 @@ struct bplist_data { | |||
| 244 | #ifdef DEBUG | 244 | #ifdef DEBUG |
| 245 | static int plist_bin_debug = 0; | 245 | static int plist_bin_debug = 0; |
| 246 | #define PLIST_BIN_ERR(...) if (plist_bin_debug) { fprintf(stderr, "libplist[binparser] ERROR: " __VA_ARGS__); } | 246 | #define PLIST_BIN_ERR(...) if (plist_bin_debug) { fprintf(stderr, "libplist[binparser] ERROR: " __VA_ARGS__); } |
| 247 | #define PLIST_BIN_WRITE_ERR(...) if (plist_bin_debug) { fprintf(stderr, "libplist[binwriter] ERROR: " __VA_ARGS__); } | ||
| 247 | #else | 248 | #else |
| 248 | #define PLIST_BIN_ERR(...) | 249 | #define PLIST_BIN_ERR(...) |
| 250 | #define PLIST_BIN_WRITE_ERR(...) | ||
| 249 | #endif | 251 | #endif |
| 250 | 252 | ||
| 251 | void plist_bin_init(void) | 253 | void plist_bin_init(void) |
| @@ -997,35 +999,53 @@ struct serialize_s | |||
| 997 | { | 999 | { |
| 998 | ptrarray_t* objects; | 1000 | ptrarray_t* objects; |
| 999 | hashtable_t* ref_table; | 1001 | hashtable_t* ref_table; |
| 1002 | hashtable_t* in_stack; | ||
| 1000 | }; | 1003 | }; |
| 1001 | 1004 | ||
| 1002 | static void serialize_plist(node_t node, void* data) | 1005 | static plist_err_t serialize_plist(node_t node, void* data) |
| 1003 | { | 1006 | { |
| 1004 | uint64_t *index_val = NULL; | 1007 | uint64_t *index_val = NULL; |
| 1005 | struct serialize_s *ser = (struct serialize_s *) data; | 1008 | struct serialize_s *ser = (struct serialize_s *) data; |
| 1006 | uint64_t current_index = ser->objects->len; | ||
| 1007 | 1009 | ||
| 1008 | //first check that node is not yet in objects | 1010 | // circular reference check: is node on current recursion stack? |
| 1011 | if (hash_table_lookup(ser->in_stack, node)) { | ||
| 1012 | PLIST_BIN_WRITE_ERR("circular reference detected\n"); | ||
| 1013 | return PLIST_ERR_CIRCULAR_REF; | ||
| 1014 | } | ||
| 1015 | |||
| 1016 | // first check that node is not yet in objects | ||
| 1009 | void* val = hash_table_lookup(ser->ref_table, node); | 1017 | void* val = hash_table_lookup(ser->ref_table, node); |
| 1010 | if (val) | 1018 | if (val) { |
| 1011 | { | 1019 | // data is already in table |
| 1012 | //data is already in table | 1020 | return PLIST_ERR_SUCCESS; |
| 1013 | return; | ||
| 1014 | } | 1021 | } |
| 1015 | //insert new ref | 1022 | |
| 1023 | // mark as active | ||
| 1024 | hash_table_insert(ser->in_stack, node, (void*)1); | ||
| 1025 | |||
| 1026 | // insert new ref | ||
| 1016 | index_val = (uint64_t *) malloc(sizeof(uint64_t)); | 1027 | index_val = (uint64_t *) malloc(sizeof(uint64_t)); |
| 1017 | assert(index_val != NULL); | 1028 | assert(index_val != NULL); |
| 1018 | *index_val = current_index; | 1029 | *index_val = ser->objects->len; |
| 1019 | hash_table_insert(ser->ref_table, node, index_val); | 1030 | hash_table_insert(ser->ref_table, node, index_val); |
| 1020 | 1031 | ||
| 1021 | //now append current node to object array | 1032 | // now append current node to object array |
| 1022 | ptr_array_add(ser->objects, node); | 1033 | ptr_array_add(ser->objects, node); |
| 1023 | 1034 | ||
| 1024 | //now recurse on children | 1035 | // now recurse on children |
| 1025 | node_t ch; | 1036 | node_t ch; |
| 1037 | plist_err_t err = PLIST_ERR_SUCCESS; | ||
| 1026 | for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) { | 1038 | for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) { |
| 1027 | serialize_plist(ch, data); | 1039 | err = serialize_plist(ch, data); |
| 1040 | if (err != PLIST_ERR_SUCCESS) { | ||
| 1041 | break; | ||
| 1042 | } | ||
| 1028 | } | 1043 | } |
| 1044 | |||
| 1045 | // leave recursion stack | ||
| 1046 | hash_table_remove(ser->in_stack, node); | ||
| 1047 | |||
| 1048 | return err; | ||
| 1029 | } | 1049 | } |
| 1030 | 1050 | ||
| 1031 | #define Log2(x) ((x) == 8 ? 3 : ((x) == 4 ? 2 : ((x) == 2 ? 1 : 0))) | 1051 | #define Log2(x) ((x) == 8 ? 3 : ((x) == 4 ? 2 : ((x) == 2 ? 1 : 0))) |
| @@ -1251,6 +1271,7 @@ plist_err_t plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length) | |||
| 1251 | { | 1271 | { |
| 1252 | ptrarray_t* objects = NULL; | 1272 | ptrarray_t* objects = NULL; |
| 1253 | hashtable_t* ref_table = NULL; | 1273 | hashtable_t* ref_table = NULL; |
| 1274 | hashtable_t* in_stack = NULL; | ||
| 1254 | struct serialize_s ser_s; | 1275 | struct serialize_s ser_s; |
| 1255 | uint8_t offset_size = 0; | 1276 | uint8_t offset_size = 0; |
| 1256 | uint8_t ref_size = 0; | 1277 | uint8_t ref_size = 0; |
| @@ -1280,11 +1301,28 @@ plist_err_t plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length) | |||
| 1280 | ptr_array_free(objects); | 1301 | ptr_array_free(objects); |
| 1281 | return PLIST_ERR_NO_MEM; | 1302 | return PLIST_ERR_NO_MEM; |
| 1282 | } | 1303 | } |
| 1304 | //hashtable for circular reference detection | ||
| 1305 | in_stack = hash_table_new(plist_node_ptr_hash, plist_node_ptr_compare, NULL); | ||
| 1306 | if (!in_stack) { | ||
| 1307 | ptr_array_free(objects); | ||
| 1308 | hash_table_destroy(ref_table); | ||
| 1309 | return PLIST_ERR_NO_MEM; | ||
| 1310 | } | ||
| 1283 | 1311 | ||
| 1284 | //serialize plist | 1312 | //serialize plist |
| 1285 | ser_s.objects = objects; | 1313 | ser_s.objects = objects; |
| 1286 | ser_s.ref_table = ref_table; | 1314 | ser_s.ref_table = ref_table; |
| 1287 | serialize_plist((node_t)plist, &ser_s); | 1315 | ser_s.in_stack = in_stack; |
| 1316 | plist_err_t err = serialize_plist((node_t)plist, &ser_s); | ||
| 1317 | if (err != PLIST_ERR_SUCCESS) { | ||
| 1318 | ptr_array_free(objects); | ||
| 1319 | hash_table_destroy(ref_table); | ||
| 1320 | hash_table_destroy(in_stack); | ||
| 1321 | return err; | ||
| 1322 | } | ||
| 1323 | //no longer needed | ||
| 1324 | hash_table_destroy(in_stack); | ||
| 1325 | ser_s.in_stack = NULL; | ||
| 1288 | 1326 | ||
| 1289 | //now stream to output buffer | 1327 | //now stream to output buffer |
| 1290 | offset_size = 0; //unknown yet | 1328 | offset_size = 0; //unknown yet |
