summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Nikias Bassen2018-12-10 01:40:56 +0100
committerGravatar Nikias Bassen2018-12-10 01:40:56 +0100
commit71dd25e14616bd261c3b6c80ff990cd1078266f6 (patch)
tree1d95c664a9bd18eb49604fb92fe0e0be3fa0969e
parentaf994607c799f3bfcbab280ef97e3bd85fe69ed2 (diff)
downloadlibplist-71dd25e14616bd261c3b6c80ff990cd1078266f6.tar.gz
libplist-71dd25e14616bd261c3b6c80ff990cd1078266f6.tar.bz2
bplist: Improve performance and memory usage when writing binary plist
-rw-r--r--src/bplist.c86
-rw-r--r--src/bytearray.c4
-rw-r--r--src/bytearray.h2
-rw-r--r--src/strbuf.h2
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)