From 71dd25e14616bd261c3b6c80ff990cd1078266f6 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 10 Dec 2018 01:40:56 +0100 Subject: bplist: Improve performance and memory usage when writing binary plist --- src/bplist.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- src/bytearray.c | 4 +-- src/bytearray.h | 2 +- src/strbuf.h | 2 +- 4 files changed, 88 insertions(+), 6 deletions(-) diff --git a/src/bplist.c b/src/bplist.c index c4fe3df..69f3dca 100644 --- a/src/bplist.c +++ b/src/bplist.c @@ -1184,7 +1184,7 @@ PLIST_API void plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length) return; //list of objects - objects = ptr_array_new(256); + objects = ptr_array_new(4096); //hashtable to write only once same nodes ref_table = hash_table_new(plist_data_hash, plist_data_compare, free); @@ -1201,8 +1201,90 @@ PLIST_API void plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length) root_object = 0; //root is first in list offset_table_index = 0; //unknown yet + //figure out the storage size required + size_t req = 0; + for (i = 0; i < num_objects; i++) + { + node_t* node = ptr_array_index(objects, i); + plist_data_t data = plist_get_data(node); + uint64_t size; + uint8_t bsize; + switch (data->type) + { + case PLIST_BOOLEAN: + req += 1; + break; + case PLIST_KEY: + case PLIST_STRING: + req += 1; + if (data->length >= 15) { + bsize = get_needed_bytes(data->length); + if (bsize == 3) bsize = 4; + req += 1; + req += bsize; + } + if ( is_ascii_string(data->strval, data->length) ) + { + req += data->length; + } + else + { + req += data->length * 2; + } + break; + case PLIST_REAL: + size = get_real_bytes(data->realval); + req += 1; + req += size; + break; + case PLIST_DATE: + req += 9; + break; + case PLIST_ARRAY: + size = node_n_children(node); + req += 1; + if (size >= 15) { + bsize = get_needed_bytes(size); + if (bsize == 3) bsize = 4; + req += 1; + req += bsize; + } + req += size * ref_size; + break; + case PLIST_DICT: + size = node_n_children(node) / 2; + req += 1; + if (size >= 15) { + bsize = get_needed_bytes(size); + if (bsize == 3) bsize = 4; + req += 1; + req += bsize; + } + req += size * 2 * ref_size; + break; + default: + size = data->length; + req += 1; + if (size >= 15) { + bsize = get_needed_bytes(size); + if (bsize == 3) bsize = 4; + req += 1; + req += bsize; + } + req += data->length; + break; + } + } + // add size of magic + req += BPLIST_MAGIC_SIZE; + req += BPLIST_VERSION_SIZE; + // add size of offset table + req += get_needed_bytes(req) * num_objects; + // add size of trailer + req += sizeof(bplist_trailer_t); + //setup a dynamic bytes array to store bplist in - bplist_buff = byte_array_new(); + bplist_buff = byte_array_new(req); //set magic number and version byte_array_append(bplist_buff, BPLIST_MAGIC, BPLIST_MAGIC_SIZE); diff --git a/src/bytearray.c b/src/bytearray.c index fff5089..7d0549b 100644 --- a/src/bytearray.c +++ b/src/bytearray.c @@ -23,10 +23,10 @@ #define PAGE_SIZE 4096 -bytearray_t *byte_array_new() +bytearray_t *byte_array_new(size_t initial) { bytearray_t *a = (bytearray_t*)malloc(sizeof(bytearray_t)); - a->capacity = PAGE_SIZE * 8; + a->capacity = (initial > PAGE_SIZE) ? (initial+(PAGE_SIZE-1)) & (~(PAGE_SIZE-1)) : PAGE_SIZE; a->data = malloc(a->capacity); a->len = 0; return a; diff --git a/src/bytearray.h b/src/bytearray.h index aae8c31..312e2aa 100644 --- a/src/bytearray.h +++ b/src/bytearray.h @@ -28,7 +28,7 @@ typedef struct bytearray_t { size_t capacity; } bytearray_t; -bytearray_t *byte_array_new(); +bytearray_t *byte_array_new(size_t initial); void byte_array_free(bytearray_t *ba); void byte_array_grow(bytearray_t *ba, size_t amount); void byte_array_append(bytearray_t *ba, void *buf, size_t len); diff --git a/src/strbuf.h b/src/strbuf.h index ba2c909..b805892 100644 --- a/src/strbuf.h +++ b/src/strbuf.h @@ -26,7 +26,7 @@ typedef struct bytearray_t strbuf_t; -#define str_buf_new() byte_array_new() +#define str_buf_new() byte_array_new(32768) #define str_buf_free(__ba) byte_array_free(__ba) #define str_buf_grow(__ba, __am) byte_array_grow(__ba, __am) #define str_buf_append(__ba, __str, __len) byte_array_append(__ba, (void*)(__str), __len) -- cgit v1.1-32-gdbae