bplist: Improve performance and memory usage when writing binary plist
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 @@
         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 @@
     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 @@
 	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)