Rename PLIST_UINT to PLIST_INT and add plist_new_int() and plist_get_int_val()

This properly supports getting and setting signed or unsigned integer values.
Also, a new helper function plist_int_val_is_negative() was added to determine if
a given #PLIST_INT node has a negative value or not.

The old type PLIST_UINT is defined as a macro with the value of PLIST_INT for
backwards compatibility.

This commit also adds int vs. uint support to the C++ interface, and the python
bindings in a hopefully useful way.
diff --git a/cython/plist.pxd b/cython/plist.pxd
index b11d80d..5a41bf8 100644
--- a/cython/plist.pxd
+++ b/cython/plist.pxd
@@ -19,7 +19,8 @@
 
 cdef class Integer(Node):
     cpdef set_value(self, object value)
-    cpdef uint64_t get_value(self)
+    cpdef get_value(self)
+    cpdef bint is_negative(self)
 
 cdef class Uid(Node):
     cpdef set_value(self, object value)
diff --git a/cython/plist.pyx b/cython/plist.pyx
index 38415f9..5481308 100644
--- a/cython/plist.pyx
+++ b/cython/plist.pyx
@@ -5,7 +5,7 @@
 cdef extern from *:
     ctypedef enum plist_type:
         PLIST_BOOLEAN,
-        PLIST_UINT,
+        PLIST_INT,
         PLIST_REAL,
         PLIST_STRING,
         PLIST_ARRAY,
@@ -14,6 +14,7 @@
         PLIST_DATA,
         PLIST_KEY,
         PLIST_UID,
+        PLIST_NULL,
         PLIST_NONE
 
     plist_t plist_new_bool(uint8_t val)
@@ -24,6 +25,10 @@
     void plist_get_uint_val(plist_t node, uint64_t *val)
     void plist_set_uint_val(plist_t node, uint64_t val)
 
+    plist_t plist_new_int(int64_t val)
+    void plist_get_int_val(plist_t node, int64_t *val)
+    void plist_set_int_val(plist_t node, int64_t val)
+
     plist_t plist_new_real(double val)
     void plist_get_real_val(plist_t node, double *val)
     void plist_set_real_val(plist_t node, double val)
@@ -47,6 +52,8 @@
     void plist_get_data_val(plist_t node, char **val, uint64_t * length)
     void plist_set_data_val(plist_t node, char *val, uint64_t length)
 
+    plist_t plist_new_null();
+
     plist_t plist_new_dict()
     int plist_dict_get_size(plist_t node)
     plist_t plist_dict_get_item(plist_t node, char* key)
@@ -77,6 +84,8 @@
     void plist_from_xml(char *plist_xml, uint32_t length, plist_t * plist)
     void plist_from_bin(char *plist_bin, uint32_t length, plist_t * plist)
 
+    int plist_int_val_is_negative(plist_t node);
+
 cdef class Node:
     def __init__(self, *args, **kwargs):
         self._c_managed = True
@@ -177,13 +186,15 @@
 cdef class Integer(Node):
     def __cinit__(self, object value=None, *args, **kwargs):
         if value is None:
-            self._c_node = plist_new_uint(0)
+            self._c_node = plist_new_int(0)
         else:
-            self._c_node = plist_new_uint(int(value))
+            if value < 0 or value <= INT64_MAX:
+                self._c_node = plist_new_int(int(value))
+            else:
+                self._c_node = plist_new_uint(int(value))
 
     def __repr__(self):
-        cdef uint64_t i = self.get_value()
-        return '<Integer: %s>' % i
+        return '<Integer: %s>' % self.get_value()
 
     def __int__(self):
         return self.get_value()
@@ -210,10 +221,18 @@
     cpdef set_value(self, object value):
         plist_set_uint_val(self._c_node, int(value))
 
-    cpdef uint64_t get_value(self):
-        cdef uint64_t value
-        plist_get_uint_val(self._c_node, &value)
-        return value
+    cpdef get_value(self):
+        cdef int64_t ivalue
+        cdef uint64_t uvalue
+        if self.is_negative():
+            plist_get_int_val(self._c_node, &ivalue)
+            return int(ivalue)
+        else:
+            plist_get_uint_val(self._c_node, &uvalue)
+            return int(uvalue)
+
+    cpdef bint is_negative(self):
+        return plist_int_val_is_negative(self._c_node);
 
 cdef Integer Integer_factory(plist_t c_node, bint managed=True):
     cdef Integer instance = Integer.__new__(Integer)
@@ -314,6 +333,20 @@
     instance._c_node = c_node
     return instance
 
+cdef class Null(Node):
+    def __cinit__(self, object value=None, *args, **kwargs):
+        self._c_node = plist_new_null()
+
+    def __repr__(self):
+        cdef uint64_t i = self.get_value()
+        return '<Null>'
+
+cdef Null Null_factory(plist_t c_node, bint managed=True):
+    cdef Null instance = Null.__new__(Null)
+    instance._c_managed = managed
+    instance._c_node = c_node
+    return instance
+
 from cpython cimport PY_MAJOR_VERSION
 
 cdef class Key(Node):
@@ -833,7 +866,7 @@
     cdef plist_type t = plist_get_node_type(c_plist)
     if t == PLIST_BOOLEAN:
         return Bool_factory(c_plist, managed)
-    if t == PLIST_UINT:
+    if t == PLIST_INT:
         return Integer_factory(c_plist, managed)
     if t == PLIST_KEY:
         return Key_factory(c_plist, managed)
@@ -851,6 +884,8 @@
         return Data_factory(c_plist, managed)
     if t == PLIST_UID:
         return Uid_factory(c_plist, managed)
+    if t == PLIST_NULL:
+        return Null_factory(c_plist, managed)
     if t == PLIST_NONE:
         return None
 
diff --git a/include/plist/Integer.h b/include/plist/Integer.h
index bdabc6f..1a4d980 100644
--- a/include/plist/Integer.h
+++ b/include/plist/Integer.h
@@ -35,12 +35,18 @@
     Integer(const Integer& i);
     Integer& operator=(const Integer& i);
     Integer(uint64_t i);
+    Integer(int64_t i);
     virtual ~Integer();
 
     Node* Clone() const;
 
+    void SetValue(int64_t i);
     void SetValue(uint64_t i);
-    uint64_t GetValue() const;
+    void SetUnsignedValue(uint64_t i);
+    int64_t GetValue() const;
+    uint64_t GetUnsignedValue() const;
+
+    bool isNegative() const;
 };
 
 };
diff --git a/include/plist/plist.h b/include/plist/plist.h
index 0ae8889..2bb947f 100644
--- a/include/plist/plist.h
+++ b/include/plist/plist.h
@@ -3,7 +3,7 @@
  * @brief Main include of libplist
  * \internal
  *
- * Copyright (c) 2012-2019 Nikias Bassen, All Rights Reserved.
+ * Copyright (c) 2012-2023 Nikias Bassen, All Rights Reserved.
  * Copyright (c) 2008-2009 Jonathan Beck, All Rights Reserved.
  *
  * This library is free software; you can redistribute it and/or
@@ -104,7 +104,7 @@
     typedef enum
     {
         PLIST_BOOLEAN,  /**< Boolean, scalar type */
-        PLIST_UINT,     /**< Unsigned integer, scalar type */
+        PLIST_INT,      /**< Integer, scalar type */
         PLIST_REAL,     /**< Real, scalar type */
         PLIST_STRING,   /**< ASCII string, scalar type */
         PLIST_ARRAY,    /**< Ordered array, structured type */
@@ -117,6 +117,9 @@
         PLIST_NONE      /**< No type */
     } plist_type;
 
+    /* for backwards compatibility */
+    #define PLIST_UINT PLIST_INT
+
     /**
      * libplist error values
      */
@@ -171,15 +174,28 @@
     plist_t plist_new_bool(uint8_t val);
 
     /**
-     * Create a new plist_t type #PLIST_UINT
+     * Create a new plist_t type #PLIST_INT with an unsigned integer value
      *
      * @param val the unsigned integer value
      * @return the created item
      * @sa #plist_type
+     * @note The value is always stored as uint64_t internally.
+     *    Use #plist_get_uint_val or #plist_get_int_val to get the unsigned or signed value.
      */
     plist_t plist_new_uint(uint64_t val);
 
     /**
+     * Create a new plist_t type #PLIST_INT with a signed integer value
+     *
+     * @param val the signed integer value
+     * @return the created item
+     * @sa #plist_type
+     * @note The value is always stored as uint64_t internally.
+     *    Use #plist_get_uint_val or #plist_get_int_val to get the unsigned or signed value.
+     */
+    plist_t plist_new_int(int64_t val);
+
+    /**
      * Create a new plist_t type #PLIST_REAL
      *
      * @param val the real value
@@ -509,8 +525,8 @@
     void plist_get_bool_val(plist_t node, uint8_t * val);
 
     /**
-     * Get the value of a #PLIST_UINT node.
-     * This function does nothing if node is not of type #PLIST_UINT
+     * Get the unsigned integer value of a #PLIST_INT node.
+     * This function does nothing if node is not of type #PLIST_INT
      *
      * @param node the node
      * @param val a pointer to a uint64_t variable.
@@ -518,6 +534,15 @@
     void plist_get_uint_val(plist_t node, uint64_t * val);
 
     /**
+     * Get the signed integer value of a #PLIST_INT node.
+     * This function does nothing if node is not of type #PLIST_INT
+     *
+     * @param node the node
+     * @param val a pointer to a int64_t variable.
+     */
+    void plist_get_int_val(plist_t node, int64_t * val);
+
+    /**
      * Get the value of a #PLIST_REAL node.
      * This function does nothing if node is not of type #PLIST_REAL
      *
@@ -607,7 +632,7 @@
 
     /**
      * Set the value of a node.
-     * Forces type of node to #PLIST_UINT
+     * Forces type of node to #PLIST_INT
      *
      * @param node the node
      * @param val the unsigned integer value
@@ -616,6 +641,15 @@
 
     /**
      * Set the value of a node.
+     * Forces type of node to #PLIST_INT
+     *
+     * @param node the node
+     * @param val the signed integer value
+     */
+    void plist_set_int_val(plist_t node, int64_t val);
+
+    /**
+     * Set the value of a node.
      * Forces type of node to #PLIST_REAL
      *
      * @param node the node
@@ -823,7 +857,7 @@
 
     /* Helper macros for the different plist types */
     #define PLIST_IS_BOOLEAN(__plist) _PLIST_IS_TYPE(__plist, BOOLEAN)
-    #define PLIST_IS_UINT(__plist)    _PLIST_IS_TYPE(__plist, UINT)
+    #define PLIST_IS_INT(__plist)     _PLIST_IS_TYPE(__plist, INT)
     #define PLIST_IS_REAL(__plist)    _PLIST_IS_TYPE(__plist, REAL)
     #define PLIST_IS_STRING(__plist)  _PLIST_IS_TYPE(__plist, STRING)
     #define PLIST_IS_ARRAY(__plist)   _PLIST_IS_TYPE(__plist, ARRAY)
@@ -832,21 +866,42 @@
     #define PLIST_IS_DATA(__plist)    _PLIST_IS_TYPE(__plist, DATA)
     #define PLIST_IS_KEY(__plist)     _PLIST_IS_TYPE(__plist, KEY)
     #define PLIST_IS_UID(__plist)     _PLIST_IS_TYPE(__plist, UID)
+    /* for backwards compatibility */
+    #define PLIST_IS_UINT             PLIST_IS_INT
 
     /**
      * Helper function to check the value of a PLIST_BOOL node.
      *
      * @param boolnode node of type PLIST_BOOL
-     * @return 1 if the boolean node has a value of TRUE, 0 if FALSE,
-     *   or -1 if the node is not of type PLIST_BOOL
+     * @return 1 if the boolean node has a value of TRUE or 0 if FALSE.
      */
     int plist_bool_val_is_true(plist_t boolnode);
 
     /**
-     * Helper function to compare the value of a PLIST_UINT node against
-     * a given value.
+     * Helper function to test if a given #PLIST_INT node's value is negative
      *
-     * @param uintnode node of type PLIST_UINT
+     * @param intnode node of type PLIST_INT
+     * @return 1 if the node's value is negative, or 0 if positive.
+     */
+    int plist_int_val_is_negative(plist_t intnode);
+
+    /**
+     * Helper function to compare the value of a PLIST_INT node against
+     * a given signed integer value.
+     *
+     * @param uintnode node of type PLIST_INT
+     * @param cmpval value to compare against
+     * @return 0 if the node's value and cmpval are equal,
+     *         1 if the node's value is greater than cmpval,
+     *         or -1 if the node's value is less than cmpval.
+     */
+    int plist_int_val_compare(plist_t uintnode, int64_t cmpval);
+
+    /**
+     * Helper function to compare the value of a PLIST_INT node against
+     * a given unsigned integer value.
+     *
+     * @param uintnode node of type PLIST_INT
      * @param cmpval value to compare against
      * @return 0 if the node's value and cmpval are equal,
      *         1 if the node's value is greater than cmpval,
diff --git a/src/Integer.cpp b/src/Integer.cpp
index a40d026..7fa0f93 100644
--- a/src/Integer.cpp
+++ b/src/Integer.cpp
@@ -24,7 +24,7 @@
 namespace PList
 {
 
-Integer::Integer(Node* parent) : Node(PLIST_UINT, parent)
+Integer::Integer(Node* parent) : Node(PLIST_INT, parent)
 {
 }
 
@@ -32,7 +32,7 @@
 {
 }
 
-Integer::Integer(const PList::Integer& i) : Node(PLIST_UINT)
+Integer::Integer(const PList::Integer& i) : Node(PLIST_INT)
 {
     plist_set_uint_val(_node, i.GetValue());
 }
@@ -44,11 +44,16 @@
     return *this;
 }
 
-Integer::Integer(uint64_t i) : Node(PLIST_UINT)
+Integer::Integer(uint64_t i) : Node(PLIST_INT)
 {
     plist_set_uint_val(_node, i);
 }
 
+Integer::Integer(int64_t i) : Node(PLIST_INT)
+{
+    plist_set_int_val(_node, i);
+}
+
 Integer::~Integer()
 {
 }
@@ -58,16 +63,38 @@
     return new Integer(*this);
 }
 
+void Integer::SetValue(int64_t i)
+{
+    plist_set_int_val(_node, i);
+}
+
 void Integer::SetValue(uint64_t i)
 {
     plist_set_uint_val(_node, i);
 }
 
-uint64_t Integer::GetValue() const
+void Integer::SetUnsignedValue(uint64_t i)
+{
+    plist_set_uint_val(_node, i);
+}
+
+int64_t Integer::GetValue() const
+{
+    int64_t i = 0;
+    plist_get_int_val(_node, &i);
+    return i;
+}
+
+uint64_t Integer::GetUnsignedValue() const
 {
     uint64_t i = 0;
     plist_get_uint_val(_node, &i);
     return i;
 }
 
+bool Integer::isNegative() const
+{
+    return plist_int_val_is_negative(_node);
+}
+
 }  // namespace PList
diff --git a/src/Key.cpp b/src/Key.cpp
index 5d7d372..5f8d205 100644
--- a/src/Key.cpp
+++ b/src/Key.cpp
@@ -32,7 +32,7 @@
 {
 }
 
-Key::Key(const PList::Key& k) : Node(PLIST_UINT)
+Key::Key(const PList::Key& k) : Node(PLIST_INT)
 {
     plist_set_key_val(_node, k.GetValue().c_str());
 }
diff --git a/src/Node.cpp b/src/Node.cpp
index fb79911..08a91b0 100644
--- a/src/Node.cpp
+++ b/src/Node.cpp
@@ -52,7 +52,7 @@
     case PLIST_BOOLEAN:
         _node = plist_new_bool(0);
         break;
-    case PLIST_UINT:
+    case PLIST_INT:
         _node = plist_new_uint(0);
         break;
     case PLIST_REAL:
@@ -134,7 +134,7 @@
         case PLIST_BOOLEAN:
             ret = new Boolean(node, parent);
             break;
-        case PLIST_UINT:
+        case PLIST_INT:
             ret = new Integer(node, parent);
             break;
         case PLIST_REAL:
diff --git a/src/Real.cpp b/src/Real.cpp
index 6bdb920..02d1d9b 100644
--- a/src/Real.cpp
+++ b/src/Real.cpp
@@ -32,7 +32,7 @@
 {
 }
 
-Real::Real(const PList::Real& d) : Node(PLIST_UINT)
+Real::Real(const PList::Real& d) : Node(PLIST_INT)
 {
     plist_set_real_val(_node, d.GetValue());
 }
diff --git a/src/String.cpp b/src/String.cpp
index 06b61ba..aee2358 100644
--- a/src/String.cpp
+++ b/src/String.cpp
@@ -32,7 +32,7 @@
 {
 }
 
-String::String(const PList::String& s) : Node(PLIST_UINT)
+String::String(const PList::String& s) : Node(PLIST_INT)
 {
     plist_set_string_val(_node, s.GetValue().c_str());
 }
diff --git a/src/bplist.c b/src/bplist.c
index 851ecd6..8927de6 100644
--- a/src/bplist.c
+++ b/src/bplist.c
@@ -62,7 +62,7 @@
     BPLIST_FALSE = 0x08,
     BPLIST_TRUE = 0x09,
     BPLIST_FILL = 0x0F,			/* will be used for length grabbing */
-    BPLIST_UINT = 0x10,
+    BPLIST_INT = 0x10,
     BPLIST_REAL = 0x20,
     BPLIST_DATE = 0x30,
     BPLIST_DATA = 0x40,
@@ -229,7 +229,7 @@
 
 static plist_t parse_bin_node_at_index(struct bplist_data *bplist, uint32_t node_index);
 
-static plist_t parse_uint_node(const char **bnode, uint8_t size)
+static plist_t parse_int_node(const char **bnode, uint8_t size)
 {
     plist_data_t data = plist_new_plist_data();
 
@@ -254,7 +254,7 @@
     data->intval = UINT_TO_HOST(*bnode, size);
 
     (*bnode) += size;
-    data->type = PLIST_UINT;
+    data->type = PLIST_INT;
 
     return node_create(NULL, data);
 }
@@ -583,8 +583,8 @@
         case BPLIST_DICT:
         {
             uint16_t next_size = **object & BPLIST_FILL;
-            if ((**object & BPLIST_MASK) != BPLIST_UINT) {
-                PLIST_BIN_ERR("%s: invalid size node type for node type 0x%02x: found 0x%02x, expected 0x%02x\n", __func__, type, **object & BPLIST_MASK, BPLIST_UINT);
+            if ((**object & BPLIST_MASK) != BPLIST_INT) {
+                PLIST_BIN_ERR("%s: invalid size node type for node type 0x%02x: found 0x%02x, expected 0x%02x\n", __func__, type, **object & BPLIST_MASK, BPLIST_INT);
                 return NULL;
             }
             (*object)++;
@@ -641,12 +641,12 @@
             return NULL;
         }
 
-    case BPLIST_UINT:
+    case BPLIST_INT:
         if (pobject + (uint64_t)(1 << size) > poffset_table) {
-            PLIST_BIN_ERR("%s: BPLIST_UINT data bytes point outside of valid range\n", __func__);
+            PLIST_BIN_ERR("%s: BPLIST_INT data bytes point outside of valid range\n", __func__);
             return NULL;
         }
-        return parse_uint_node(object, size);
+        return parse_int_node(object, size);
 
     case BPLIST_REAL:
         if (pobject + (uint64_t)(1 << size) > poffset_table) {
@@ -896,7 +896,7 @@
     switch (data->type)
     {
     case PLIST_BOOLEAN:
-    case PLIST_UINT:
+    case PLIST_INT:
     case PLIST_REAL:
     case PLIST_DATE:
     case PLIST_UID:
@@ -973,7 +973,7 @@
     //do not write 3bytes int node
     if (size == 3)
         size++;
-    sz = BPLIST_UINT | Log2(size);
+    sz = BPLIST_INT | Log2(size);
 
     val = be64toh(val);
     byte_array_append(bplist, &sz, 1);
@@ -982,7 +982,7 @@
 
 static void write_uint(bytearray_t * bplist, uint64_t val)
 {
-    uint8_t sz = BPLIST_UINT | 4;
+    uint8_t sz = BPLIST_INT | 4;
     uint64_t zero = 0;
 
     val = be64toh(val);
@@ -1346,7 +1346,7 @@
             byte_array_append(bplist_buff, &b, 1);
             break;
         }
-        case PLIST_UINT:
+        case PLIST_INT:
             if (data->length == 16) {
                 write_uint(bplist_buff, data->intval);
             } else {
diff --git a/src/jplist.c b/src/jplist.c
index f4adf2f..7817b1c 100644
--- a/src/jplist.c
+++ b/src/jplist.c
@@ -131,7 +131,7 @@
         str_buf_append(*outbuf, "null", 4);
 	break;
 
-    case PLIST_UINT:
+    case PLIST_INT:
         val = (char*)malloc(64);
         if (node_data->length == 16) {
             val_len = snprintf(val, 64, "%"PRIu64, node_data->intval);
@@ -349,7 +349,7 @@
             *size += data->length;
             *size += 2;
             break;
-        case PLIST_UINT:
+        case PLIST_INT:
             if (data->length == 16) {
                 *size += num_digits_u(data->intval);
             } else {
@@ -501,10 +501,15 @@
         val = plist_new_node(data);
     } else if (isdigit(str_val[0]) || (str_val[0] == '-' && str_val+1 < str_end && isdigit(str_val[1]))) {
         char* endp = (char*)str_val;
+        int is_neg = (str_val[0] == '-');
         int64_t intpart = parse_decimal(str_val, str_end, &endp);
         if (endp >= str_end) {
             /* integer */
-            val = plist_new_uint((uint64_t)intpart);
+            if (is_neg || intpart <= INT64_MAX) {
+                val = plist_new_int(intpart);
+            } else {
+                val = plist_new_uint((uint64_t)intpart);
+            }
         } else if ((*endp == '.' && endp+1 < str_end && isdigit(*(endp+1))) || ((*endp == 'e' || *endp == 'E') && endp+1 < str_end && (isdigit(*(endp+1)) || ((*(endp+1) == '-') && endp+2 < str_end && isdigit(*(endp+2)))))) {
             /* floating point */
             double dval = (double)intpart;
@@ -513,7 +518,6 @@
             do {
                 if (*endp == '.') {
                     fendp++;
-                    int is_neg = (str_val[0] == '-');
                     double frac = 0;
                     double p = 0.1;
                     while (fendp < str_end && isdigit(*fendp)) {
diff --git a/src/oplist.c b/src/oplist.c
index 122440f..8936cce 100644
--- a/src/oplist.c
+++ b/src/oplist.c
@@ -146,7 +146,7 @@
 
     switch (node_data->type)
     {
-    case PLIST_UINT:
+    case PLIST_INT:
         val = (char*)malloc(64);
         if (node_data->length == 16) {
             val_len = snprintf(val, 64, "%"PRIu64, node_data->intval);
@@ -393,7 +393,7 @@
             *size += data->length;
             *size += 2;
             break;
-        case PLIST_UINT:
+        case PLIST_INT:
             if (data->length == 16) {
                 *size += num_digits_u(data->intval);
             } else {
diff --git a/src/plist.c b/src/plist.c
index e696f70..5d06311 100644
--- a/src/plist.c
+++ b/src/plist.c
@@ -2,7 +2,7 @@
  * plist.c
  * Builds plist XML structures
  *
- * Copyright (c) 2009-2019 Nikias Bassen, All Rights Reserved.
+ * Copyright (c) 2009-2023 Nikias Bassen, All Rights Reserved.
  * Copyright (c) 2010-2015 Martin Szulecki, All Rights Reserved.
  * Copyright (c) 2008 Zach C., All Rights Reserved.
  *
@@ -390,7 +390,16 @@
 PLIST_API plist_t plist_new_uint(uint64_t val)
 {
     plist_data_t data = plist_new_plist_data();
-    data->type = PLIST_UINT;
+    data->type = PLIST_INT;
+    data->intval = val;
+    data->length = (val > INT_MAX) ? sizeof(uint64_t)*2 : sizeof(uint64_t);
+    return plist_new_node(data);
+}
+
+PLIST_API plist_t plist_new_int(int64_t val)
+{
+    plist_data_t data = plist_new_plist_data();
+    data->type = PLIST_INT;
     data->intval = val;
     data->length = sizeof(uint64_t);
     return plist_new_node(data);
@@ -926,7 +935,7 @@
     case PLIST_BOOLEAN:
         *((char *) value) = data->boolval;
         break;
-    case PLIST_UINT:
+    case PLIST_INT:
     case PLIST_UID:
         *((uint64_t *) value) = data->intval;
         break;
@@ -1024,12 +1033,17 @@
         return;
     plist_type type = plist_get_node_type(node);
     uint64_t length = 0;
-    if (PLIST_UINT != type)
+    if (PLIST_INT != type)
         return;
     plist_get_type_and_value(node, &type, (void *) val, &length);
     assert(length == sizeof(uint64_t) || length == 16);
 }
 
+PLIST_API void plist_get_int_val(plist_t node, int64_t * val)
+{
+    plist_get_uint_val(node, (uint64_t*)val);
+}
+
 PLIST_API void plist_get_uid_val(plist_t node, uint64_t * val)
 {
     if (!node || !val)
@@ -1116,7 +1130,7 @@
     switch (val_a->type)
     {
     case PLIST_BOOLEAN:
-    case PLIST_UINT:
+    case PLIST_INT:
     case PLIST_REAL:
     case PLIST_DATE:
     case PLIST_UID:
@@ -1180,7 +1194,7 @@
     case PLIST_BOOLEAN:
         data->boolval = *((char *) value);
         break;
-    case PLIST_UINT:
+    case PLIST_INT:
     case PLIST_UID:
         data->intval = *((uint64_t *) value);
         break;
@@ -1225,7 +1239,12 @@
 
 PLIST_API void plist_set_uint_val(plist_t node, uint64_t val)
 {
-    plist_set_element_val(node, PLIST_UINT, &val, sizeof(uint64_t));
+    plist_set_element_val(node, PLIST_INT, &val, (val > INT64_MAX) ? sizeof(uint64_t)*2 : sizeof(uint64_t));
+}
+
+PLIST_API void plist_set_int_val(plist_t node, int64_t val)
+{
+    plist_set_element_val(node, PLIST_INT, &val, sizeof(uint64_t));
 }
 
 PLIST_API void plist_set_uid_val(plist_t node, uint64_t val)
@@ -1259,9 +1278,42 @@
     return (bv == 1);
 }
 
+PLIST_API int plist_int_val_is_negative(plist_t intnode)
+{
+    if (!PLIST_IS_INT(intnode)) {
+        return 0;
+    }
+    plist_data_t data = plist_get_data(intnode);
+    if (data->length == 16) {
+        return 0;
+    }
+    if ((int64_t)data->intval < 0) {
+        return 1;
+    }
+    return 0;
+}
+
+PLIST_API int plist_int_val_compare(plist_t uintnode, int64_t cmpval)
+{
+    if (!PLIST_IS_INT(uintnode)) {
+        return -1;
+    }
+    int64_t uintval = 0;
+    plist_get_int_val(uintnode, &uintval);
+    if (uintval == cmpval) {
+        return 0;
+    }
+
+    if (uintval < cmpval) {
+        return -1;
+    }
+
+    return 1;
+}
+
 PLIST_API int plist_uint_val_compare(plist_t uintnode, uint64_t cmpval)
 {
-    if (!PLIST_IS_UINT(uintnode)) {
+    if (!PLIST_IS_INT(uintnode)) {
         return -1;
     }
     uint64_t uintval = 0;
diff --git a/src/xplist.c b/src/xplist.c
index d8f6458..cf5d818 100644
--- a/src/xplist.c
+++ b/src/xplist.c
@@ -162,7 +162,7 @@
     }
     break;
 
-    case PLIST_UINT:
+    case PLIST_INT:
         tag = XPLIST_INT;
         tag_len = XPLIST_INT_LEN;
         val = (char*)malloc(64);
@@ -479,7 +479,7 @@
             *size += data->length;
             *size += (XPLIST_KEY_LEN << 1) + 6;
             break;
-        case PLIST_UINT:
+        case PLIST_INT:
             if (data->length == 16) {
                 *size += num_digits_u(data->intval);
             } else {
@@ -1194,7 +1194,7 @@
                     data->intval = 0;
                     data->length = 8;
                 }
-                data->type = PLIST_UINT;
+                data->type = PLIST_INT;
             } else if (!strcmp(tag, XPLIST_REAL)) {
                 if (!is_empty) {
                     text_part_t first_part = { NULL, 0, 0, NULL };
diff --git a/test/Makefile.am b/test/Makefile.am
index 66543ea..5326317 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -8,6 +8,7 @@
 noinst_PROGRAMS = \
 	plist_cmp \
 	plist_test \
+	integer_set_test \
 	plist_btest \
 	plist_jtest \
 	plist_otest
@@ -20,6 +21,9 @@
 plist_test_SOURCES = plist_test.c
 plist_test_LDADD = $(top_builddir)/src/libplist-2.0.la
 
+integer_set_test_SOURCES = integer_set.c
+integer_set_test_LDADD = $(top_builddir)/src/libplist-2.0.la
+
 plist_btest_SOURCES = plist_btest.c
 plist_btest_LDADD = $(top_builddir)/src/libplist-2.0.la
 
@@ -54,6 +58,7 @@
 	refsize.test \
 	malformed_dict.test \
 	uid.test \
+	integer_set.test \
 	json1.test \
 	json2.test \
 	json3.test \
diff --git a/test/integer_set.c b/test/integer_set.c
new file mode 100644
index 0000000..e25648f
--- /dev/null
+++ b/test/integer_set.c
@@ -0,0 +1,130 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <stdlib.h>
+
+#include <string.h>
+#include <plist/plist.h>
+
+void print_plist(plist_t pl)
+{
+	char *xml = NULL;
+	uint32_t xlen = 0;
+	plist_to_xml(pl, &xml, &xlen);
+	if (xml) {
+		printf("%s\n", xml);
+	}
+	free(xml);
+}
+
+int main(int argc, char** argv)
+{
+	int err = 0;
+	char *xml = NULL;
+	uint32_t xlen = 0;
+	plist_t iii = plist_new_int(0);
+
+	/* test 1 */
+	plist_set_uint_val(iii, 0x8000000000000000LL);
+	plist_to_xml(iii, &xml, &xlen);
+	const char* match1 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+		"<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
+		"<plist version=\"1.0\">\n"
+		"<integer>9223372036854775808</integer>\n"
+		"</plist>\n";
+	if (strcmp(xml, match1) != 0) {
+		printf("ERROR: plist_set_uint_val with 0x8000000000000000LL failed\n");
+		err++;
+	} else {
+		printf("SUCCESS: plist_set_uint_val with 0x8000000000000000LL\n");
+	}
+	free(xml);
+	xml = NULL;
+
+	/* test 2 */
+	plist_set_int_val(iii, 0x8000000000000000LL);
+	plist_to_xml(iii, &xml, &xlen);
+	const char* match2 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+		"<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
+		"<plist version=\"1.0\">\n"
+		"<integer>-9223372036854775808</integer>\n"
+		"</plist>\n";
+	if (strcmp(xml, match2) != 0) {
+		printf("ERROR: plist_set_int_val with 0x8000000000000000LL failed\n");
+		err++;
+	} else {
+		printf("SUCCESS: plist_set_int_val with 0x8000000000000000LL\n");
+	}
+	free(xml);
+	xml = NULL;
+
+	/* test 3 */
+	plist_set_uint_val(iii, (uint64_t)-1LL);
+	plist_to_xml(iii, &xml, &xlen);
+	const char* match3 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+		"<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
+		"<plist version=\"1.0\">\n"
+		"<integer>18446744073709551615</integer>\n"
+		"</plist>\n";
+	if (strcmp(xml, match3) != 0) {
+		printf("ERROR: plist_set_uint_val with (uint64_t)-1LL failed\n");
+		err++;
+	} else {
+		printf("SUCCESS: plist_set_uint_val with (uint64_t)-1LL\n");
+	}
+	free(xml);
+	xml = NULL;
+
+	/* test 4 */
+	plist_set_int_val(iii, -1LL);
+	plist_to_xml(iii, &xml, &xlen);
+	const char* match4 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+		"<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
+		"<plist version=\"1.0\">\n"
+		"<integer>-1</integer>\n"
+		"</plist>\n";
+	if (strcmp(xml, match4) != 0) {
+		printf("ERROR: plist_set_int_val with -1LL failed\n");
+		err++;
+	} else {
+		printf("SUCCESS: plist_set_int_val with -1LL\n");
+	}
+	free(xml);
+	xml = NULL;
+
+	/* test 5 */
+	plist_set_uint_val(iii, 0x8000000000000001LL);
+	plist_to_xml(iii, &xml, &xlen);
+	const char* match5 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+		"<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
+		"<plist version=\"1.0\">\n"
+		"<integer>9223372036854775809</integer>\n"
+		"</plist>\n";
+	if (strcmp(xml, match5) != 0) {
+		printf("ERROR: plist_set_uint_val with 0x8000000000000001LL failed\n");
+		err++;
+	} else {
+		printf("SUCCESS: plist_set_uint_val with 0x8000000000000001LL\n");
+	}
+	free(xml);
+	xml = NULL;
+
+	/* test 6 */
+	plist_set_uint_val(iii, 18446744073709551615uLL);
+	plist_to_xml(iii, &xml, &xlen);
+	const char* match6 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+		"<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
+		"<plist version=\"1.0\">\n"
+		"<integer>18446744073709551615</integer>\n"
+		"</plist>\n";
+	if (strcmp(xml, match6) != 0) {
+		printf("ERROR: plist_set_uint_val with 0x8000000000000001LL failed\n");
+		err++;
+	} else {
+		printf("SUCCESS: plist_set_uint_val with 0x8000000000000001LL\n");
+	}
+	free(xml);
+	xml = NULL;
+
+	return (err > 0) ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/test/integer_set.test b/test/integer_set.test
new file mode 100755
index 0000000..b917663
--- /dev/null
+++ b/test/integer_set.test
@@ -0,0 +1,5 @@
+## -*- sh -*-
+
+set -e
+
+$top_builddir/test/integer_set_test