Commit 40cf910a authored by Nikias Bassen's avatar Nikias Bassen

bplist: Refactor binary plist parsing in a recursive way

parent 6a781e6f
/* /*
* plist.c * bplist.c
* Binary plist implementation * Binary plist implementation
* *
* Copyright (c) 2008 Jonathan Beck All Rights Reserved. * Copyright (c) 2011-2015 Nikias Bassen, All Rights Reserved.
* Copyright (c) 2008-2010 Jonathan Beck, All Rights Reserved.
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
...@@ -95,7 +96,7 @@ static void float_byte_convert(uint8_t * address, size_t size) ...@@ -95,7 +96,7 @@ static void float_byte_convert(uint8_t * address, size_t size)
union plist_uint_ptr union plist_uint_ptr
{ {
void *src; const void *src;
uint8_t *u8ptr; uint8_t *u8ptr;
uint16_t *u16ptr; uint16_t *u16ptr;
uint32_t *u32ptr; uint32_t *u32ptr;
...@@ -202,7 +203,20 @@ static uint32_t uint24_from_be(union plist_uint_ptr buf) ...@@ -202,7 +203,20 @@ static uint32_t uint24_from_be(union plist_uint_ptr buf)
#define NODE_IS_ROOT(x) (((node_t*)x)->isRoot) #define NODE_IS_ROOT(x) (((node_t*)x)->isRoot)
static plist_t parse_uint_node(char *bnode, uint8_t size, char **next_object) struct bplist_data {
const char* data;
uint64_t size;
uint64_t num_objects;
uint8_t dict_size;
uint8_t offset_size;
const char* offset_table;
uint32_t level;
uint32_t *used_indexes;
};
static plist_t parse_bin_node_at_index(struct bplist_data *bplist, uint32_t node_index);
static plist_t parse_uint_node(const char **bnode, uint8_t size)
{ {
plist_data_t data = plist_new_plist_data(); plist_data_t data = plist_new_plist_data();
...@@ -213,12 +227,12 @@ static plist_t parse_uint_node(char *bnode, uint8_t size, char **next_object) ...@@ -213,12 +227,12 @@ static plist_t parse_uint_node(char *bnode, uint8_t size, char **next_object)
case sizeof(uint16_t): case sizeof(uint16_t):
case sizeof(uint32_t): case sizeof(uint32_t):
case sizeof(uint64_t): case sizeof(uint64_t):
memcpy(&data->intval, bnode, size); memcpy(&data->intval, *bnode, size);
data->intval = UINT_TO_HOST(&data->intval, size); data->intval = UINT_TO_HOST(&data->intval, size);
data->length = sizeof(uint64_t); data->length = sizeof(uint64_t);
break; break;
case 16: case 16:
memcpy(&data->intval, bnode+8, sizeof(uint64_t)); memcpy(&data->intval, (*bnode)+8, sizeof(uint64_t));
data->intval = UINT_TO_HOST(&data->intval, sizeof(uint64_t)); data->intval = UINT_TO_HOST(&data->intval, sizeof(uint64_t));
data->length = size; data->length = size;
break; break;
...@@ -227,13 +241,13 @@ static plist_t parse_uint_node(char *bnode, uint8_t size, char **next_object) ...@@ -227,13 +241,13 @@ static plist_t parse_uint_node(char *bnode, uint8_t size, char **next_object)
return NULL; return NULL;
}; };
*next_object = bnode + size; (*bnode) += size;
data->type = PLIST_UINT; data->type = PLIST_UINT;
return node_create(NULL, data); return node_create(NULL, data);
} }
static plist_t parse_real_node(char *bnode, uint8_t size) static plist_t parse_real_node(const char **bnode, uint8_t size)
{ {
plist_data_t data = plist_new_plist_data(); plist_data_t data = plist_new_plist_data();
float floatval = 0.0; float floatval = 0.0;
...@@ -241,7 +255,7 @@ static plist_t parse_real_node(char *bnode, uint8_t size) ...@@ -241,7 +255,7 @@ static plist_t parse_real_node(char *bnode, uint8_t size)
size = 1 << size; // make length less misleading size = 1 << size; // make length less misleading
buf = malloc (size); buf = malloc (size);
memcpy (buf, bnode, size); memcpy (buf, *bnode, size);
switch (size) switch (size)
{ {
case sizeof(float): case sizeof(float):
...@@ -265,7 +279,7 @@ static plist_t parse_real_node(char *bnode, uint8_t size) ...@@ -265,7 +279,7 @@ static plist_t parse_real_node(char *bnode, uint8_t size)
return node_create(NULL, data); return node_create(NULL, data);
} }
static plist_t parse_date_node(char *bnode, uint8_t size) static plist_t parse_date_node(const char **bnode, uint8_t size)
{ {
plist_t node = parse_real_node(bnode, size); plist_t node = parse_real_node(bnode, size);
plist_data_t data = plist_get_data(node); plist_data_t data = plist_get_data(node);
...@@ -279,13 +293,13 @@ static plist_t parse_date_node(char *bnode, uint8_t size) ...@@ -279,13 +293,13 @@ static plist_t parse_date_node(char *bnode, uint8_t size)
return node; return node;
} }
static plist_t parse_string_node(char *bnode, uint64_t size) static plist_t parse_string_node(const char **bnode, uint64_t size)
{ {
plist_data_t data = plist_new_plist_data(); plist_data_t data = plist_new_plist_data();
data->type = PLIST_STRING; data->type = PLIST_STRING;
data->strval = (char *) malloc(sizeof(char) * (size + 1)); data->strval = (char *) malloc(sizeof(char) * (size + 1));
memcpy(data->strval, bnode, size); memcpy(data->strval, *bnode, size);
data->strval[size] = '\0'; data->strval[size] = '\0';
data->length = strlen(data->strval); data->length = strlen(data->strval);
...@@ -348,7 +362,7 @@ static char *plist_utf16_to_utf8(uint16_t *unistr, long len, long *items_read, l ...@@ -348,7 +362,7 @@ static char *plist_utf16_to_utf8(uint16_t *unistr, long len, long *items_read, l
return outbuf; return outbuf;
} }
static plist_t parse_unicode_node(char *bnode, uint64_t size) static plist_t parse_unicode_node(const char **bnode, uint64_t size)
{ {
plist_data_t data = plist_new_plist_data(); plist_data_t data = plist_new_plist_data();
uint64_t i = 0; uint64_t i = 0;
...@@ -359,7 +373,7 @@ static plist_t parse_unicode_node(char *bnode, uint64_t size) ...@@ -359,7 +373,7 @@ static plist_t parse_unicode_node(char *bnode, uint64_t size)
data->type = PLIST_STRING; data->type = PLIST_STRING;
unicodestr = (uint16_t*) malloc(sizeof(uint16_t) * size); unicodestr = (uint16_t*) malloc(sizeof(uint16_t) * size);
memcpy(unicodestr, bnode, sizeof(uint16_t) * size); memcpy(unicodestr, *bnode, sizeof(uint16_t) * size);
for (i = 0; i < size; i++) for (i = 0; i < size; i++)
byte_convert((uint8_t *) (unicodestr + i), sizeof(uint16_t)); byte_convert((uint8_t *) (unicodestr + i), sizeof(uint16_t));
...@@ -375,43 +389,112 @@ static plist_t parse_unicode_node(char *bnode, uint64_t size) ...@@ -375,43 +389,112 @@ static plist_t parse_unicode_node(char *bnode, uint64_t size)
return node_create(NULL, data); return node_create(NULL, data);
} }
static plist_t parse_data_node(char *bnode, uint64_t size) static plist_t parse_data_node(const char **bnode, uint64_t size)
{ {
plist_data_t data = plist_new_plist_data(); plist_data_t data = plist_new_plist_data();
data->type = PLIST_DATA; data->type = PLIST_DATA;
data->length = size; data->length = size;
data->buff = (uint8_t *) malloc(sizeof(uint8_t) * size); data->buff = (uint8_t *) malloc(sizeof(uint8_t) * size);
memcpy(data->buff, bnode, sizeof(uint8_t) * size); memcpy(data->buff, *bnode, sizeof(uint8_t) * size);
return node_create(NULL, data); return node_create(NULL, data);
} }
static plist_t parse_dict_node(char *bnode, uint64_t size, uint32_t ref_size) static plist_t parse_dict_node(struct bplist_data *bplist, const char** bnode, uint64_t size)
{ {
uint64_t j;
uint64_t str_i = 0, str_j = 0;
uint64_t index1, index2;
plist_data_t data = plist_new_plist_data(); plist_data_t data = plist_new_plist_data();
data->type = PLIST_DICT; data->type = PLIST_DICT;
data->length = size; data->length = size;
data->buff = (uint8_t *) malloc(sizeof(uint8_t) * size * ref_size * 2);
memcpy(data->buff, bnode, sizeof(uint8_t) * size * ref_size * 2);
return node_create(NULL, data); plist_t node = node_create(NULL, data);
for (j = 0; j < data->length; j++) {
str_i = j * bplist->dict_size;
str_j = (j + size) * bplist->dict_size;
index1 = UINT_TO_HOST((*bnode) + str_i, bplist->dict_size);
index2 = UINT_TO_HOST((*bnode) + str_j, bplist->dict_size);
if (index1 >= bplist->num_objects) {
plist_free(node);
return NULL;
}
if (index2 >= bplist->num_objects) {
plist_free(node);
return NULL;
}
/* process key node */
plist_t key = parse_bin_node_at_index(bplist, index1);
if (!key) {
plist_free(node);
return NULL;
}
/* enforce key type */
plist_get_data(key)->type = PLIST_KEY;
if (!plist_get_data(key)->strval) {
fprintf(stderr, "ERROR: Malformed binary plist dict, invalid key node encountered!\n");
plist_free(key);
plist_free(node);
return NULL;
}
/* process value node */
plist_t val = parse_bin_node_at_index(bplist, index2);
if (!val) {
plist_free(key);
plist_free(node);
return NULL;
}
node_attach(node, key);
node_attach(node, val);
}
return node;
} }
static plist_t parse_array_node(char *bnode, uint64_t size, uint32_t ref_size) static plist_t parse_array_node(struct bplist_data *bplist, const char** bnode, uint64_t size)
{ {
uint64_t j;
uint32_t str_j = 0;
uint32_t index1;
plist_data_t data = plist_new_plist_data(); plist_data_t data = plist_new_plist_data();
data->type = PLIST_ARRAY; data->type = PLIST_ARRAY;
data->length = size; data->length = size;
data->buff = (uint8_t *) malloc(sizeof(uint8_t) * size * ref_size);
memcpy(data->buff, bnode, sizeof(uint8_t) * size * ref_size);
return node_create(NULL, data); plist_t node = node_create(NULL, data);
for (j = 0; j < data->length; j++) {
str_j = j * bplist->dict_size;
index1 = UINT_TO_HOST((*bnode) + str_j, bplist->dict_size);
if (index1 >= bplist->num_objects) {
plist_free(node);
return NULL;
}
/* process value node */
plist_t val = parse_bin_node_at_index(bplist, index1);
if (!val) {
plist_free(node);
return NULL;
}
node_attach(node, val);
}
return node;
} }
static plist_t parse_uid_node(char *bnode, uint8_t size, char **next_object) static plist_t parse_uid_node(const char **bnode, uint8_t size)
{ {
plist_data_t data = plist_new_plist_data(); plist_data_t data = plist_new_plist_data();
...@@ -422,7 +505,7 @@ static plist_t parse_uid_node(char *bnode, uint8_t size, char **next_object) ...@@ -422,7 +505,7 @@ static plist_t parse_uid_node(char *bnode, uint8_t size, char **next_object)
case sizeof(uint16_t): case sizeof(uint16_t):
case sizeof(uint32_t): case sizeof(uint32_t):
case sizeof(uint64_t): case sizeof(uint64_t):
memcpy(&data->intval, bnode, size); memcpy(&data->intval, *bnode, size);
data->intval = UINT_TO_HOST(&data->intval, size); data->intval = UINT_TO_HOST(&data->intval, size);
break; break;
default: default:
...@@ -430,15 +513,13 @@ static plist_t parse_uid_node(char *bnode, uint8_t size, char **next_object) ...@@ -430,15 +513,13 @@ static plist_t parse_uid_node(char *bnode, uint8_t size, char **next_object)
return NULL; return NULL;
}; };
*next_object = bnode + size;
data->type = PLIST_UID; data->type = PLIST_UID;
data->length = sizeof(uint64_t); data->length = sizeof(uint64_t);
return node_create(NULL, data); return node_create(NULL, data);
} }
static plist_t parse_bin_node(struct bplist_data *bplist, const char** object)
static plist_t parse_bin_node(char *object, uint8_t dict_size, char **next_object)
{ {
uint16_t type = 0; uint16_t type = 0;
uint64_t size = 0; uint64_t size = 0;
...@@ -446,9 +527,9 @@ static plist_t parse_bin_node(char *object, uint8_t dict_size, char **next_objec ...@@ -446,9 +527,9 @@ static plist_t parse_bin_node(char *object, uint8_t dict_size, char **next_objec
if (!object) if (!object)
return NULL; return NULL;
type = (*object) & 0xF0; type = (**object) & BPLIST_MASK;
size = (*object) & 0x0F; size = (**object) & BPLIST_FILL;
object++; (*object)++;
switch (type) switch (type)
{ {
...@@ -481,7 +562,7 @@ static plist_t parse_bin_node(char *object, uint8_t dict_size, char **next_objec ...@@ -481,7 +562,7 @@ static plist_t parse_bin_node(char *object, uint8_t dict_size, char **next_objec
} }
case BPLIST_UINT: case BPLIST_UINT:
return parse_uint_node(object, size, next_object); return parse_uint_node(object, size);
case BPLIST_REAL: case BPLIST_REAL:
return parse_real_node(object, size); return parse_real_node(object, size);
...@@ -493,9 +574,8 @@ static plist_t parse_bin_node(char *object, uint8_t dict_size, char **next_objec ...@@ -493,9 +574,8 @@ static plist_t parse_bin_node(char *object, uint8_t dict_size, char **next_objec
return parse_date_node(object, size); return parse_date_node(object, size);
case BPLIST_DATA: case BPLIST_DATA:
if (0x0F == size) if (BPLIST_FILL == size) {
{ plist_t size_node = parse_bin_node(bplist, object);
plist_t size_node = parse_bin_node(object, dict_size, &object);
if (plist_get_node_type(size_node) != PLIST_UINT) if (plist_get_node_type(size_node) != PLIST_UINT)
return NULL; return NULL;
plist_get_uint_val(size_node, &size); plist_get_uint_val(size_node, &size);
...@@ -504,9 +584,8 @@ static plist_t parse_bin_node(char *object, uint8_t dict_size, char **next_objec ...@@ -504,9 +584,8 @@ static plist_t parse_bin_node(char *object, uint8_t dict_size, char **next_objec
return parse_data_node(object, size); return parse_data_node(object, size);
case BPLIST_STRING: case BPLIST_STRING:
if (0x0F == size) if (BPLIST_FILL == size) {
{ plist_t size_node = parse_bin_node(bplist, object);
plist_t size_node = parse_bin_node(object, dict_size, &object);
if (plist_get_node_type(size_node) != PLIST_UINT) if (plist_get_node_type(size_node) != PLIST_UINT)
return NULL; return NULL;
plist_get_uint_val(size_node, &size); plist_get_uint_val(size_node, &size);
...@@ -515,9 +594,8 @@ static plist_t parse_bin_node(char *object, uint8_t dict_size, char **next_objec ...@@ -515,9 +594,8 @@ static plist_t parse_bin_node(char *object, uint8_t dict_size, char **next_objec
return parse_string_node(object, size); return parse_string_node(object, size);
case BPLIST_UNICODE: case BPLIST_UNICODE:
if (0x0F == size) if (BPLIST_FILL == size) {
{ plist_t size_node = parse_bin_node(bplist, object);
plist_t size_node = parse_bin_node(object, dict_size, &object);
if (plist_get_node_type(size_node) != PLIST_UINT) if (plist_get_node_type(size_node) != PLIST_UINT)
return NULL; return NULL;
plist_get_uint_val(size_node, &size); plist_get_uint_val(size_node, &size);
...@@ -525,76 +603,64 @@ static plist_t parse_bin_node(char *object, uint8_t dict_size, char **next_objec ...@@ -525,76 +603,64 @@ static plist_t parse_bin_node(char *object, uint8_t dict_size, char **next_objec
} }
return parse_unicode_node(object, size); return parse_unicode_node(object, size);
case BPLIST_UNK_0x70: case BPLIST_SET:
case BPLIST_ARRAY: case BPLIST_ARRAY:
if (0x0F == size) if (BPLIST_FILL == size) {
{ plist_t size_node = parse_bin_node(bplist, object);
plist_t size_node = parse_bin_node(object, dict_size, &object);
if (plist_get_node_type(size_node) != PLIST_UINT) if (plist_get_node_type(size_node) != PLIST_UINT)
return NULL; return NULL;
plist_get_uint_val(size_node, &size); plist_get_uint_val(size_node, &size);
plist_free(size_node); plist_free(size_node);
} }
return parse_array_node(object, size, dict_size); return parse_array_node(bplist, object, size);
case BPLIST_UID: case BPLIST_UID:
return parse_uid_node(object, size, next_object); return parse_uid_node(object, size);
case BPLIST_SET:
case BPLIST_DICT: case BPLIST_DICT:
if (0x0F == size) if (BPLIST_FILL == size) {
{ plist_t size_node = parse_bin_node(bplist, object);
plist_t size_node = parse_bin_node(object, dict_size, &object);
if (plist_get_node_type(size_node) != PLIST_UINT) if (plist_get_node_type(size_node) != PLIST_UINT)
return NULL; return NULL;
plist_get_uint_val(size_node, &size); plist_get_uint_val(size_node, &size);
plist_free(size_node); plist_free(size_node);
} }
return parse_dict_node(object, size, dict_size); return parse_dict_node(bplist, object, size);
default: default:
return NULL; return NULL;
} }
return NULL; return NULL;
} }
static void* copy_plist_data(const void* src) static plist_t parse_bin_node_at_index(struct bplist_data *bplist, uint32_t node_index)
{ {
plist_data_t srcdata = (plist_data_t) src; int i;
plist_data_t dstdata = plist_new_plist_data(); const char* ptr;
plist_t plist;
dstdata->type = srcdata->type; ptr = bplist->data + UINT_TO_HOST(bplist->offset_table + node_index * bplist->offset_size, bplist->offset_size);
dstdata->length = srcdata->length; /* make sure the node offset is in a sane range */
switch (dstdata->type) if ((ptr < bplist->data) || (ptr >= bplist->offset_table)) {
{ return NULL;
case PLIST_BOOLEAN:
dstdata->boolval = srcdata->boolval;
break;
case PLIST_UINT:
dstdata->intval = srcdata->intval;
break;
case PLIST_DATE:
dstdata->timeval.tv_sec = srcdata->timeval.tv_sec;
dstdata->timeval.tv_usec = srcdata->timeval.tv_usec;
break;
case PLIST_REAL:
dstdata->realval = srcdata->realval;
break;
case PLIST_KEY:
case PLIST_STRING:
dstdata->strval = strdup(srcdata->strval);
break;
case PLIST_DATA:
dstdata->buff = (uint8_t*) malloc(sizeof(uint8_t) * srcdata->length);
memcpy(dstdata->buff, srcdata->buff, sizeof(uint8_t) * srcdata->length);
break;
case PLIST_UID:
dstdata->intval = srcdata->intval;
break;
default:
break;
} }
return dstdata; /* store node_index for current recursion level */
bplist->used_indexes[bplist->level] = node_index;
/* recursion check */
if (bplist->level > 0) {
for (i = bplist->level-1; i >= 0; i--) {
if (bplist->used_indexes[i] == bplist->used_indexes[bplist->level]) {
fprintf(stderr, "Recursion detected in binary plist. Aborting.\n");
return NULL;
}
}
}
/* finally parse node */
bplist->level++;
plist = parse_bin_node(bplist, &ptr);
bplist->level--;
return plist;
} }
PLIST_API void plist_from_bin(const char *plist_bin, uint32_t length, plist_t * plist) PLIST_API void plist_from_bin(const char *plist_bin, uint32_t length, plist_t * plist)
...@@ -602,19 +668,11 @@ PLIST_API void plist_from_bin(const char *plist_bin, uint32_t length, plist_t * ...@@ -602,19 +668,11 @@ PLIST_API void plist_from_bin(const char *plist_bin, uint32_t length, plist_t *
char *trailer = NULL; char *trailer = NULL;
uint8_t offset_size = 0; uint8_t offset_size = 0;
uint8_t dict_param_size = 0; uint8_t dict_size = 0;
uint64_t num_objects = 0; uint64_t num_objects = 0;
uint64_t root_object = 0; uint64_t root_object = 0;
uint64_t offset_table_index = 0; uint64_t offset_table_index = 0;
plist_t *nodeslist = NULL;
uint64_t i = 0;
uint64_t current_offset = 0;
char *offset_table = NULL;
uint32_t j = 0, str_i = 0, str_j = 0;
uint32_t index1 = 0, index2 = 0;
//first check we have enough data //first check we have enough data
if (!(length >= BPLIST_MAGIC_SIZE + BPLIST_VERSION_SIZE + BPLIST_TRL_SIZE)) if (!(length >= BPLIST_MAGIC_SIZE + BPLIST_VERSION_SIZE + BPLIST_TRL_SIZE))
return; return;
...@@ -629,7 +687,7 @@ PLIST_API void plist_from_bin(const char *plist_bin, uint32_t length, plist_t * ...@@ -629,7 +687,7 @@ PLIST_API void plist_from_bin(const char *plist_bin, uint32_t length, plist_t *
trailer = (char *) (plist_bin + (length - BPLIST_TRL_SIZE)); trailer = (char *) (plist_bin + (length - BPLIST_TRL_SIZE));
offset_size = trailer[BPLIST_TRL_OFFSIZE_IDX]; offset_size = trailer[BPLIST_TRL_OFFSIZE_IDX];
dict_param_size = trailer[BPLIST_TRL_PARMSIZE_IDX]; dict_size = trailer[BPLIST_TRL_PARMSIZE_IDX];
num_objects = be64dec(trailer + BPLIST_TRL_NUMOBJ_IDX); num_objects = be64dec(trailer + BPLIST_TRL_NUMOBJ_IDX);
root_object = be64dec(trailer + BPLIST_TRL_ROOTOBJ_IDX); root_object = be64dec(trailer + BPLIST_TRL_ROOTOBJ_IDX);
offset_table_index = be64dec(trailer + BPLIST_TRL_OFFTAB_IDX); offset_table_index = be64dec(trailer + BPLIST_TRL_OFFTAB_IDX);
...@@ -637,122 +695,22 @@ PLIST_API void plist_from_bin(const char *plist_bin, uint32_t length, plist_t * ...@@ -637,122 +695,22 @@ PLIST_API void plist_from_bin(const char *plist_bin, uint32_t length, plist_t *
if (num_objects == 0) if (num_objects == 0)
return; return;
//allocate serialized array of nodes if (root_object >= num_objects)
nodeslist = (plist_t *) malloc(sizeof(plist_t) * num_objects);
if (!nodeslist)
return; return;
//parse serialized nodes struct bplist_data bplist;
offset_table = (char *) (plist_bin + offset_table_index); bplist.data = plist_bin;
for (i = 0; i < num_objects; i++) bplist.size = length;
{ bplist.num_objects = num_objects;
char *obj = NULL; bplist.dict_size = dict_size;
current_offset = UINT_TO_HOST(offset_table + i * offset_size, offset_size); bplist.offset_size = offset_size;
bplist.offset_table = (char *) (plist_bin + offset_table_index);
obj = (char *) (plist_bin + current_offset); bplist.level = 0;
nodeslist[i] = parse_bin_node(obj, dict_param_size, &obj); bplist.used_indexes = (uint32_t*)malloc(sizeof(uint32_t) * num_objects);
}
//setup children for structured types
for (i = 0; i < num_objects; i++)
{
plist_data_t data = plist_get_data(nodeslist[i]);
if (!data) {
break;
}
switch (data->type) *plist = parse_bin_node_at_index(&bplist, root_object);
{
case PLIST_DICT:
for (j = 0; j < data->length; j++)
{
node_t* n = NULL;
str_i = j * dict_param_size;
str_j = (j + data->length) * dict_param_size;
index1 = UINT_TO_HOST(data->buff + str_i, dict_param_size);
index2 = UINT_TO_HOST(data->buff + str_j, dict_param_size);
// process key node
if (index1 < num_objects)
{
// is node already attached?
if (NODE_IS_ROOT(nodeslist[index1])) {
// use original
n = nodeslist[index1];
} else {
// use a copy, because this node is already attached elsewhere
n = node_copy_deep(nodeslist[index1], copy_plist_data);
}
// enforce key type
plist_get_data(n)->type = PLIST_KEY;
// attach key node
node_attach(nodeslist[i], n);
}
// process value node
if (index2 < num_objects)
{
// is node already attached?
if (NODE_IS_ROOT(nodeslist[index2])) {
// use original
n = nodeslist[index2];
} else {
// use a copy, because this node is already attached elsewhere
n = node_copy_deep(nodeslist[index2], copy_plist_data);
// ensure key type is never used for values, especially if we copy a key node
if (plist_get_data(n)->type == PLIST_KEY) {
plist_get_data(n)->type = PLIST_STRING;
}
}
// attach value node
node_attach(nodeslist[i], n);
}
}
break;
case PLIST_ARRAY: free(bplist.used_indexes);
for (j = 0; j < data->length; j++)
{
str_j = j * dict_param_size;
index1 = UINT_TO_HOST(data->buff + str_j, dict_param_size);
if (index1 < num_objects)
{
if (NODE_IS_ROOT(nodeslist[index1]))
node_attach(nodeslist[i], nodeslist[index1]);
else
node_attach(nodeslist[i], node_copy_deep(nodeslist[index1], copy_plist_data));
}
}
break;
default:
break;
}
}
*plist = nodeslist[root_object];
// free unreferenced nodes that would otherwise leak memory
for (i = 0; i < num_objects; i++) {
plist_data_t data = plist_get_data(nodeslist[i]);
if ((data->type == PLIST_DICT) || (data->type == PLIST_ARRAY)) {
free(data->buff);
data->buff = NULL;
}
if (i == root_object) continue;
node_t* node = (node_t*)nodeslist[i];
if (node && NODE_IS_ROOT(node)) {
plist_free(node);
}
}
free(nodeslist);
} }
static unsigned int plist_data_hash(const void* key) static unsigned int plist_data_hash(const void* key)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment