From d886885b0ec2506fa2caf0986a3d0e496fea91c2 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 16 Jan 2023 04:25:52 +0100 Subject: 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. --- cython/plist.pxd | 3 +- cython/plist.pyx | 55 ++++++++++++++++---- include/plist/Integer.h | 8 ++- include/plist/plist.h | 79 ++++++++++++++++++++++++----- src/Integer.cpp | 35 +++++++++++-- src/Key.cpp | 2 +- src/Node.cpp | 4 +- src/Real.cpp | 2 +- src/String.cpp | 2 +- src/bplist.c | 24 ++++----- src/jplist.c | 12 +++-- src/oplist.c | 4 +- src/plist.c | 68 ++++++++++++++++++++++--- src/xplist.c | 6 +-- test/Makefile.am | 5 ++ test/integer_set.c | 130 ++++++++++++++++++++++++++++++++++++++++++++++++ test/integer_set.test | 5 ++ 17 files changed, 382 insertions(+), 62 deletions(-) create mode 100644 test/integer_set.c create mode 100755 test/integer_set.test 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 Bool(Node): 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 @@ from libc.stdint cimport * cdef extern from *: ctypedef enum plist_type: PLIST_BOOLEAN, - PLIST_UINT, + PLIST_INT, PLIST_REAL, PLIST_STRING, PLIST_ARRAY, @@ -14,6 +14,7 @@ cdef extern from *: PLIST_DATA, PLIST_KEY, PLIST_UID, + PLIST_NULL, PLIST_NONE plist_t plist_new_bool(uint8_t val) @@ -24,6 +25,10 @@ cdef extern from *: 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 @@ cdef extern from *: 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 @@ cdef extern from *: 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 Bool Bool_factory(plist_t c_node, bint managed=True): 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 '' % i + return '' % self.get_value() def __int__(self): return self.get_value() @@ -210,10 +221,18 @@ cdef class Integer(Node): 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 @@ cdef Uid Uid_factory(plist_t c_node, bint managed=True): 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 '' + +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 object plist_t_to_node(plist_t c_plist, bint managed=True): 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 @@ cdef object plist_t_to_node(plist_t c_plist, bint managed=True): 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 @@ public : 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 @@ extern "C" 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 @@ extern "C" PLIST_NONE /**< No type */ } plist_type; + /* for backwards compatibility */ + #define PLIST_UINT PLIST_INT + /** * libplist error values */ @@ -171,14 +174,27 @@ extern "C" 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 * @@ -509,14 +525,23 @@ extern "C" 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. */ 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,13 +632,22 @@ extern "C" /** * 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 */ void plist_set_uint_val(plist_t node, uint64_t val); + /** + * 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 @@ -823,7 +857,7 @@ extern "C" /* 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 @@ extern "C" #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 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_UINT + * @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(plist_t node, Node* parent) : Node(node, parent) { } -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 @@ Integer& Integer::operator=(const PList::Integer& i) 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 @@ Node* Integer::Clone() const 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(plist_t node, Node* parent) : Node(node, parent) { } -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 @@ Node::Node(plist_type type, Node* parent) : _parent(parent) 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 @@ Node* Node::FromPlist(plist_t node, Node* parent) 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(plist_t node, Node* parent) : Node(node, parent) { } -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(plist_t node, Node* parent) : Node(node, parent) { } -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 @@ enum 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 @@ void plist_bin_deinit(void) 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 @@ static plist_t parse_uint_node(const char **bnode, uint8_t size) 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 @@ static plist_t parse_bin_node(struct bplist_data *bplist, const char** object) 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 @@ static plist_t parse_bin_node(struct bplist_data *bplist, const char** object) 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 @@ static unsigned int plist_data_hash(const void* key) 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 @@ static void write_int(bytearray_t * bplist, uint64_t val) //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_int(bytearray_t * bplist, uint64_t val) 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 @@ PLIST_API plist_err_t plist_to_bin(plist_t plist, char **plist_bin, uint32_t * l 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 @@ static int node_to_json(node_t* node, bytearray_t **outbuf, uint32_t depth, int 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 @@ static int node_estimate_size(node_t *node, uint64_t *size, uint32_t depth, int *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 @@ static plist_t parse_primitive(const char* js, jsmntok_info_t* ti, int* index) 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 @@ static plist_t parse_primitive(const char* js, jsmntok_info_t* ti, int* index) 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 @@ static int node_to_openstep(node_t* node, bytearray_t **outbuf, uint32_t depth, 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 @@ static int node_estimate_size(node_t *node, uint64_t *size, uint32_t depth, int *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_bool(uint8_t val) 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 @@ static void plist_get_type_and_value(plist_t node, plist_type * type, void *valu 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 @@ PLIST_API void plist_get_uint_val(plist_t node, uint64_t * val) 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 @@ int plist_data_compare(const void *a, const void *b) 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 @@ static void plist_set_element_val(plist_t node, plist_type type, const void *val 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_bool_val(plist_t node, uint8_t val) 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 @@ PLIST_API int plist_bool_val_is_true(plist_t boolnode) 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 @@ static int node_to_xml(node_t* node, bytearray_t **outbuf, uint32_t depth) } break; - case PLIST_UINT: + case PLIST_INT: tag = XPLIST_INT; tag_len = XPLIST_INT_LEN; val = (char*)malloc(64); @@ -479,7 +479,7 @@ static int node_estimate_size(node_t *node, uint64_t *size, uint32_t depth) *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 @@ static int node_from_xml(parse_ctx ctx, plist_t *plist) 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 @@ AM_LDFLAGS = noinst_PROGRAMS = \ plist_cmp \ plist_test \ + integer_set_test \ plist_btest \ plist_jtest \ plist_otest @@ -20,6 +21,9 @@ plist_cmp_LDADD = \ 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 @@ TESTS = \ 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 +#include +#include +#include + +#include +#include + +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 = "\n" + "\n" + "\n" + "9223372036854775808\n" + "\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 = "\n" + "\n" + "\n" + "-9223372036854775808\n" + "\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 = "\n" + "\n" + "\n" + "18446744073709551615\n" + "\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 = "\n" + "\n" + "\n" + "-1\n" + "\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 = "\n" + "\n" + "\n" + "9223372036854775809\n" + "\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 = "\n" + "\n" + "\n" + "18446744073709551615\n" + "\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 -- cgit v1.1-32-gdbae