summaryrefslogtreecommitdiffstats
path: root/src/bplist.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/bplist.c')
-rw-r--r--src/bplist.c64
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
245static int plist_bin_debug = 0; 245static 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
251void plist_bin_init(void) 253void 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
1002static void serialize_plist(node_t node, void* data) 1005static 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