From 458341fcc360db6e0bac0619e2512e6050f4e8c7 Mon Sep 17 00:00:00 2001
From: Nikias Bassen <nikias@gmx.li>
Date: Sat, 28 Jan 2017 04:44:05 +0100
Subject: [PATCH] bplist: Improve real/date node de/serialization

---
 src/bplist.c | 121 +++++++++++++++++++++++++++--------------------------------
 1 file changed, 56 insertions(+), 65 deletions(-)

diff --git a/src/bplist.c b/src/bplist.c
index 9e6e261..a2fb9be 100644
--- a/src/bplist.c
+++ b/src/bplist.c
@@ -75,25 +75,6 @@ enum
     BPLIST_MASK = 0xF0
 };
 
-static void float_byte_convert(uint8_t * address, size_t size)
-{
-#if (defined(__LITTLE_ENDIAN__) \
-		&& !defined(__FLOAT_WORD_ORDER__)) \
-	|| (defined(__FLOAT_WORD_ORDER__) \
-		&& __FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__)
-    uint8_t i = 0, j = 0;
-    uint8_t tmp = 0;
-
-    for (i = 0; i < (size / 2); i++)
-    {
-        tmp = address[i];
-        j = ((size - 1) + 0) - i;
-        address[i] = address[j];
-        address[j] = tmp;
-    }
-#endif
-}
-
 union plist_uint_ptr
 {
     const void *src;
@@ -128,11 +109,33 @@ static void byte_convert(uint8_t * address, size_t size)
 #endif
 }
 
+#ifndef bswap16
+#define bswap16(x)   ((((x) & 0xFF00) >> 8) | (((x) & 0x00FF) << 8))
+#endif
+
+#ifndef bswap32
+#define bswap32(x)   ((((x) & 0xFF000000) >> 24) \
+                    | (((x) & 0x00FF0000) >>  8) \
+                    | (((x) & 0x0000FF00) <<  8) \
+                    | (((x) & 0x000000FF) << 24))
+#endif
+
+#ifndef bswap64
+#define bswap64(x)   ((((x) & 0xFF00000000000000ull) >> 56) \
+                    | (((x) & 0x00FF000000000000ull) >> 40) \
+                    | (((x) & 0x0000FF0000000000ull) >> 24) \
+                    | (((x) & 0x000000FF00000000ull) >>  8) \
+                    | (((x) & 0x00000000FF000000ull) <<  8) \
+                    | (((x) & 0x0000000000FF0000ull) << 24) \
+                    | (((x) & 0x000000000000FF00ull) << 40) \
+                    | (((x) & 0x00000000000000FFull) << 56))
+#endif
+
 #ifndef be16toh
 #ifdef __BIG_ENDIAN__
 #define be16toh(x) (x)
 #else
-#define be16toh(x) ((((x) & 0xFF00) >> 8) | (((x) & 0x00FF) << 8))
+#define be16toh(x) bswap16(x)
 #endif
 #endif
 
@@ -140,10 +143,7 @@ static void byte_convert(uint8_t * address, size_t size)
 #ifdef __BIG_ENDIAN__
 #define be32toh(x) (x)
 #else
-#define be32toh(x) ((((x) & 0xFF000000) >> 24) \
-                    | (((x) & 0x00FF0000) >> 8) \
-                    | (((x) & 0x0000FF00) << 8) \
-                    | (((x) & 0x000000FF) << 24))
+#define be32toh(x) bswap32(x)
 #endif
 #endif
 
@@ -151,14 +151,7 @@ static void byte_convert(uint8_t * address, size_t size)
 #ifdef __BIG_ENDIAN__
 #define be64toh(x) (x)
 #else
-#define be64toh(x) ((((x) & 0xFF00000000000000ull) >> 56) \
-                    | (((x) & 0x00FF000000000000ull) >> 40) \
-                    | (((x) & 0x0000FF0000000000ull) >> 24) \
-                    | (((x) & 0x000000FF00000000ull) >> 8) \
-                    | (((x) & 0x00000000FF000000ull) << 8) \
-                    | (((x) & 0x0000000000FF0000ull) << 24) \
-                    | (((x) & 0x000000000000FF00ull) << 40) \
-                    | (((x) & 0x00000000000000FFull) << 56)) 
+#define be64toh(x) bswap64(x)
 #endif
 #endif
 
@@ -186,7 +179,19 @@ static void byte_convert(uint8_t * address, size_t size)
 		( ((uint64_t)x) < (1ULL << 24) ? 3 : \
 		( ((uint64_t)x) < (1ULL << 32) ? 4 : 8))))
 
-#define get_real_bytes(x) (x == (float) x ? 4 : 8)
+#define get_real_bytes(x) (x == (float) x ? sizeof(float) : sizeof(double))
+
+#if (defined(__LITTLE_ENDIAN__) \
+     && !defined(__FLOAT_WORD_ORDER__)) \
+ || (defined(__FLOAT_WORD_ORDER__) \
+     && __FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+#define float_bswap64(x) bswap64(x)
+#define float_bswap32(x) bswap32(x)
+#else
+#define float_bswap64(x) (x)
+#define float_bswap32(x) (x)
+#endif
+
 
 #define NODE_IS_ROOT(x) (((node_t*)x)->isRoot)
 
@@ -235,29 +240,23 @@ static plist_t parse_uint_node(const 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();
-    float floatval = 0.0;
-    uint8_t* buf;
+    uint8_t buf[8];
 
     size = 1 << size;			// make length less misleading
-    buf = malloc (size);
-    memcpy (buf, *bnode, size);
     switch (size)
     {
-    case sizeof(float):
-        float_byte_convert(buf, size);
-        floatval = *(float *) buf;
-        data->realval = floatval;
+    case sizeof(uint32_t):
+        *(uint32_t*)buf = float_bswap32(*(uint32_t*)*bnode);
+        data->realval = *(float *) buf;
         break;
-    case sizeof(double):
-        float_byte_convert(buf, size);
+    case sizeof(uint64_t):
+        *(uint64_t*)buf = float_bswap64(*(uint64_t*)*bnode);
         data->realval = *(double *) buf;
         break;
     default:
-        free(buf);
         free(data);
         return NULL;
     }
-    free (buf);
     data->type = PLIST_REAL;
     data->length = sizeof(double);
 
@@ -872,32 +871,24 @@ static void write_uint(bytearray_t * bplist, uint64_t val)
 
 static void write_real(bytearray_t * bplist, double val)
 {
-    uint64_t size = get_real_bytes(val);	//cheat to know used space
-    uint8_t *buff = (uint8_t *) malloc(sizeof(uint8_t) + size);
+    int size = get_real_bytes(val);	//cheat to know used space
+    uint8_t buff[9];
     buff[0] = BPLIST_REAL | Log2(size);
-    if (size == sizeof(double))
-    {
-        memcpy(buff + 1, &val, size);
-    }
-    else if (size == sizeof(float))
-    {
-        float tmpval = (float) val;
-        memcpy(buff + 1, &tmpval, size);
+    if (size == sizeof(float)) {
+        float floatval = (float)val;
+        *(uint32_t*)(buff+1) = float_bswap32(*(uint32_t*)&floatval);
+    } else {
+        *(uint64_t*)(buff+1) = float_bswap64(*(uint64_t*)&val);
     }
-    float_byte_convert(buff + 1, size);
-    byte_array_append(bplist, buff, sizeof(uint8_t) + size);
-    free(buff);
+    byte_array_append(bplist, buff, size+1);
 }
 
 static void write_date(bytearray_t * bplist, double val)
 {
-    uint64_t size = 8;			//dates always use 8 bytes
-    uint8_t *buff = (uint8_t *) malloc(sizeof(uint8_t) + size);
-    buff[0] = BPLIST_DATE | Log2(size);
-    memcpy(buff + 1, &val, size);
-    float_byte_convert(buff + 1, size);
-    byte_array_append(bplist, buff, sizeof(uint8_t) + size);
-    free(buff);
+    uint8_t buff[9];
+    buff[0] = BPLIST_DATE | 3;
+    *(uint64_t*)(buff+1) = float_bswap64(*(uint64_t*)&val);
+    byte_array_append(bplist, buff, sizeof(buff));
 }
 
 static void write_raw_data(bytearray_t * bplist, uint8_t mark, uint8_t * val, uint64_t size)
