From 6c0bf73f0773873edf8754246c291235aa217e7a Mon Sep 17 00:00:00 2001
From: Nikias Bassen <nikias@gmx.li>
Date: Fri, 23 May 2014 11:01:57 +0200
Subject: [PATCH] Handle signed vs. unsigned integer values correctly

---
 src/bplist.c | 27 +++++++++++++++++++++++++--
 src/xplist.c | 31 ++++++++++++++++++++++++++++---
 2 files changed, 53 insertions(+), 5 deletions(-)

diff --git a/src/bplist.c b/src/bplist.c
index d1694b9..c4b2e13 100644
--- a/src/bplist.c
+++ b/src/bplist.c
@@ -212,6 +212,12 @@ static plist_t parse_uint_node(char *bnode, uint8_t size, char **next_object)
     case sizeof(uint64_t):
         memcpy(&data->intval, bnode, size);
         data->intval = UINT_TO_HOST(&data->intval, size);
+        data->length = sizeof(uint64_t);
+        break;
+    case 16:
+        memcpy(&data->intval, bnode+8, sizeof(uint64_t));
+        data->intval = UINT_TO_HOST(&data->intval, sizeof(uint64_t));
+        data->length = size;
         break;
     default:
         free(data);
@@ -220,7 +226,6 @@ static plist_t parse_uint_node(char *bnode, uint8_t size, char **next_object)
 
     *next_object = bnode + size;
     data->type = PLIST_UINT;
-    data->length = sizeof(uint64_t);
 
     return node_create(NULL, data);
 }
@@ -833,6 +838,20 @@ static void write_int(bytearray_t * bplist, uint64_t val)
     free(buff);
 }
 
+static void write_uint(bytearray_t * bplist, uint64_t val)
+{
+    uint64_t size = 16;
+    uint8_t *buff = NULL;
+
+    buff = (uint8_t *) malloc(sizeof(uint8_t) + size);
+    buff[0] = BPLIST_UINT | 4;
+    memset(buff + 1, '\0', 8);
+    memcpy(buff + 9, &val, 8);
+    byte_convert(buff + 9, 8);
+    byte_array_append(bplist, buff, sizeof(uint8_t) + size);
+    free(buff);
+}
+
 static void write_real(bytearray_t * bplist, double val)
 {
     uint64_t size = get_real_bytes(val);	//cheat to know used space
@@ -1143,7 +1162,11 @@ void plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length)
             break;
 
         case PLIST_UINT:
-            write_int(bplist_buff, data->intval);
+            if (data->length == 16) {
+                write_uint(bplist_buff, data->intval);
+            } else {
+                write_int(bplist_buff, data->intval);
+            }
             break;
 
         case PLIST_REAL:
diff --git a/src/xplist.c b/src/xplist.c
index d953e23..eaa2468 100644
--- a/src/xplist.c
+++ b/src/xplist.c
@@ -184,7 +184,11 @@ static void node_to_xml(node_t* node, void *xml_struct)
     case PLIST_UINT:
         tag = XPLIST_INT;
         val = (char*)malloc(64);
-        (void)snprintf(val, 64, "%"PRIu64, node_data->intval);
+        if (node_data->length == 16) {
+	        (void)snprintf(val, 64, "%"PRIu64, node_data->intval);
+	} else {
+	        (void)snprintf(val, 64, "%"PRIi64, node_data->intval);
+	}
         break;
 
     case PLIST_REAL:
@@ -377,9 +381,30 @@ static void xml_to_node(xmlNodePtr xml_node, plist_t * plist_node)
         if (!xmlStrcmp(node->name, XPLIST_INT))
         {
             xmlChar *strval = xmlNodeGetContent(node);
-            data->intval = strtoull((char*)strval, NULL, 0);
+            int is_negative = 0;
+            char *str = (char*)strval;
+            if ((str[0] == '-') || (str[0] == '+')) {
+                if (str[0] == '-') {
+                    is_negative = 1;
+                }
+                str++;
+            }
+            char* endp = NULL;
+            data->intval = strtoull((char*)str, &endp, 0);
+            if ((endp != NULL) && (strlen(endp) > 0)) {
+                fprintf(stderr, "%s: integer parse error: string contains invalid characters: '%s'\n", __func__, endp);
+            }
+            if (is_negative || (data->intval <= INT64_MAX)) {
+                int64_t v = data->intval;
+                if (is_negative) {
+                    v = -v;
+                }
+                data->intval = (uint64_t)v;
+                data->length = 8;
+            } else {
+                data->length = 16;
+            }
             data->type = PLIST_UINT;
-            data->length = 8;
             xmlFree(strval);
             continue;
         }
