From 2ca52d65bb113e8639e732f67fec3c3223c0a444 Mon Sep 17 00:00:00 2001 From: Bryan Forbes Date: Mon, 26 Sep 2011 17:14:39 +0200 Subject: Added cython bindings. --- cython/plist.pyx | 699 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 699 insertions(+) create mode 100644 cython/plist.pyx (limited to 'cython/plist.pyx') diff --git a/cython/plist.pyx b/cython/plist.pyx new file mode 100644 index 0000000..a1282e7 --- /dev/null +++ b/cython/plist.pyx @@ -0,0 +1,699 @@ +cdef extern from *: + ctypedef unsigned char uint8_t + ctypedef short int int16_t + ctypedef unsigned short int uint16_t + ctypedef unsigned int uint32_t + ctypedef int int32_t +IF UNAME_MACHINE == 'x86_64': + ctypedef unsigned long int uint64_t +ELSE: + ctypedef unsigned long long int uint64_t + +cimport python_unicode + +cdef extern from *: + ctypedef enum plist_type: + PLIST_BOOLEAN, + PLIST_UINT, + PLIST_REAL, + PLIST_STRING, + PLIST_ARRAY, + PLIST_DICT, + PLIST_DATE, + PLIST_DATA, + PLIST_KEY, + PLIST_NONE + + plist_t plist_new_bool(uint8_t val) + void plist_get_bool_val(plist_t node, uint8_t *val) + void plist_set_bool_val(plist_t node, uint8_t val) + + plist_t plist_new_uint(uint64_t val) + 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_real(double val) + void plist_get_real_val(plist_t node, double *val) + void plist_set_real_val(plist_t node, double val) + + plist_t plist_new_date(int32_t sec, int32_t usec) + void plist_get_date_val(plist_t node, int32_t * sec, int32_t * usec) + void plist_set_date_val(plist_t node, int32_t sec, int32_t usec) + + plist_t plist_new_string(char *val) + void plist_get_string_val(plist_t node, char **val) + void plist_set_string_val(plist_t node, char *val) + + plist_t plist_new_data(char *val, uint64_t length) + 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_dict() + int plist_dict_get_size(plist_t node) + plist_t plist_dict_get_item(plist_t node, char* key) + void plist_dict_set_item(plist_t node, char* key, plist_t item) + void plist_dict_insert_item(plist_t node, char* key, plist_t item) + void plist_dict_remove_item(plist_t node, char* key) + + void plist_dict_new_iter(plist_t node, plist_dict_iter *iter) + void plist_dict_next_item(plist_t node, plist_dict_iter iter, char **key, plist_t *val) + + plist_t plist_new_array() + uint32_t plist_array_get_size(plist_t node) + plist_t plist_array_get_item(plist_t node, uint32_t n) + uint32_t plist_array_get_item_index(plist_t node) + void plist_array_set_item(plist_t node, plist_t item, uint32_t n) + void plist_array_append_item(plist_t node, plist_t item) + void plist_array_insert_item(plist_t node, plist_t item, uint32_t n) + void plist_array_remove_item(plist_t node, uint32_t n) + + void plist_free(plist_t plist) + plist_t plist_copy(plist_t plist) + void plist_to_xml(plist_t plist, char **plist_xml, uint32_t *length) + void plist_to_bin(plist_t plist, char **plist_bin, uint32_t *length) + + plist_t plist_get_parent(plist_t node) + plist_type plist_get_node_type(plist_t node) + + void plist_set_type(plist_t node, plist_type type) + + 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) + +cdef extern from *: + void free(void *ptr) + +cdef class Node: + def __init__(self, *args, **kwargs): + self._c_managed = True + + def __dealloc__(self): + if self._c_node is not NULL and self._c_managed: + plist_free(self._c_node) + + cpdef object __deepcopy__(self, memo={}): + return plist_t_to_node(plist_copy(self._c_node)) + + cpdef object copy(self): + cdef plist_t c_node = NULL + c_node = plist_copy(self._c_node) + return plist_t_to_node(c_node) + + cpdef bytes to_xml(self): + cdef char* out = NULL + cdef uint32_t length + plist_to_xml(self._c_node, &out, &length) + + return out[:length] + + cpdef bytes to_bin(self): + cdef char* out = NULL + cdef uint32_t length + plist_to_bin(self._c_node, &out, &length) + + return out[:length] + + property parent: + def __get__(self): + cdef plist_t c_parent = NULL + cdef Node node + + c_parent = plist_get_parent(self._c_node) + if c_parent == NULL: + return None + + return plist_t_to_node(c_parent) + + def __str__(self): + return str(self.get_value()) + +cdef class Bool(Node): + def __cinit__(self, value=None, *args, **kwargs): + if value is None: + self._c_node = plist_new_bool(0) + else: + self._c_node = plist_new_bool(bool(value)) + + def __nonzero__(self): + return self.get_value() + + def __richcmp__(self, other, op): + cdef bool b = self.get_value() + if op == 0: + return b < other + if op == 1: + return b <= other + if op == 2: + return b == other + if op == 3: + return b != other + if op == 4: + return b > other + if op == 5: + return b >= other + + def __repr__(self): + b = self.get_value() + return '' % b + + cpdef set_value(self, value): + plist_set_bool_val(self._c_node, bool(value)) + + cpdef bool get_value(self): + cdef uint8_t value + plist_get_bool_val(self._c_node, &value) + return bool(value) + +cdef Bool Bool_factory(plist_t c_node, bool managed=True): + cdef Bool instance = Bool.__new__(Bool) + instance._c_managed = managed + instance._c_node = c_node + return instance + +cdef class Integer(Node): + def __cinit__(self, value=None, *args, **kwargs): + if value is None: + self._c_node = plist_new_uint(0) + else: + self._c_node = plist_new_uint(int(value)) + + def __repr__(self): + i = self.get_value() + return '' % i + + def __int__(self): + return self.get_value() + + def __float__(self): + return float(self.get_value()) + + def __richcmp__(self, other, op): + cdef int i = self.get_value() + if op == 0: + return i < other + if op == 1: + return i <= other + if op == 2: + return i == other + if op == 3: + return i != other + if op == 4: + return i > other + if op == 5: + return i >= other + + cpdef set_value(self, value): + plist_set_uint_val(self._c_node, int(value)) + + cpdef int get_value(self): + cdef uint64_t value + plist_get_uint_val(self._c_node, &value) + return value + +cdef Integer Integer_factory(plist_t c_node, bool managed=True): + cdef Integer instance = Integer.__new__(Integer) + instance._c_managed = managed + instance._c_node = c_node + return instance + +cdef class Real(Node): + def __cinit__(self, value=None, *args, **kwargs): + if value is None: + self._c_node = plist_new_real(0.0) + else: + self._c_node = plist_new_real(float(value)) + + def __repr__(self): + r = self.get_value() + return '' % r + + def __float__(self): + return self.get_value() + + def __int__(self): + return int(self.get_value()) + + def __richcmp__(self, other, op): + cdef float f = self.get_value() + if op == 0: + return f < other + if op == 1: + return f <= other + if op == 2: + return f == other + if op == 3: + return f != other + if op == 4: + return f > other + if op == 5: + return f >= other + + cpdef set_value(self, value): + plist_set_real_val(self._c_node, float(value)) + + cpdef float get_value(self): + cdef double value + plist_get_real_val(self._c_node, &value) + return value + +cdef Real Real_factory(plist_t c_node, bool managed=True): + cdef Real instance = Real.__new__(Real) + instance._c_managed = managed + instance._c_node = c_node + return instance + +from python_version cimport PY_MAJOR_VERSION + +cdef class String(Node): + def __cinit__(self, value=None, *args, **kwargs): + if value is None: + self._c_node = plist_new_string("") + else: + if isinstance(value, unicode): + utf8_data = value.encode('utf-8') + elif (PY_MAJOR_VERSION < 3) and isinstance(value, str): + value.decode('ascii') + utf8_data = value + else: + raise ValueError("requires text input, got %s" % type(value)) + self._c_node = plist_new_string(utf8_data) + + def __repr__(self): + s = self.get_value() + return '' % s + + def __richcmp__(self, other, op): + cdef str s = self.get_value() + if op == 0: + return s < other + if op == 1: + return s <= other + if op == 2: + return s == other + if op == 3: + return s != other + if op == 4: + return s > other + if op == 5: + return s >= other + + cpdef set_value(self, unicode value): + if value is None: + self._c_node = plist_new_string("") + else: + if isinstance(value, unicode): + utf8_data = value.encode('utf-8') + elif (PY_MAJOR_VERSION < 3) and isinstance(value, str): + value.decode('ascii') + utf8_data = value + else: + raise ValueError("requires text input, got %s" % type(value)) + self._c_node = plist_new_string(utf8_data) + + cpdef unicode get_value(self): + cdef char* value = NULL + plist_get_string_val(self._c_node, &value) + return python_unicode.PyUnicode_DecodeUTF8(value, len(value), 'strict') + +cdef String String_factory(plist_t c_node, bool managed=True): + cdef String instance = String.__new__(String) + instance._c_managed = managed + instance._c_node = c_node + return instance + +cdef extern from "plist_util.h": + void datetime_to_ints(object obj, int32_t* sec, int32_t* usec) + object ints_to_datetime(int32_t sec, int32_t usec) + int check_datetime(object obj) + +cdef plist_t create_date_plist(value=None): + cdef plist_t node = NULL + cdef int32_t secs + cdef int32_t usecs + if value is None: + node = plist_new_date(0, 0) + elif check_datetime(value): + datetime_to_ints(value, &secs, &usecs) + node = plist_new_date(secs, usecs) + return node + +cdef class Date(Node): + def __cinit__(self, value=None, *args, **kwargs): + self._c_node = create_date_plist(value) + + def __repr__(self): + d = self.get_value() + return '' % d.ctime() + + def __richcmp__(self, other, op): + d = self.get_value() + if op == 0: + return d < other + if op == 1: + return d <= other + if op == 2: + return d == other + if op == 3: + return d != other + if op == 4: + return d > other + if op == 5: + return d >= other + + cpdef object get_value(self): + cdef int32_t secs = 0 + cdef int32_t usecs = 0 + cdef object result + plist_get_date_val(self._c_node, &secs, &usecs) + return ints_to_datetime(secs, usecs) + + cpdef set_value(self, value): + cdef int32_t secs + cdef int32_t usecs + if not check_datetime(value): + raise ValueError("Expected a datetime") + datetime_to_ints(value, &secs, &usecs) + plist_set_date_val(self._c_node, secs, usecs) + +cdef Date Date_factory(plist_t c_node, bool managed=True): + cdef Date instance = Date.__new__(Date) + instance._c_managed = managed + instance._c_node = c_node + return instance + +cdef class Data(Node): + def __cinit__(self, value=None, *args, **kwargs): + if value is None: + self._c_node = plist_new_data(NULL, 0) + else: + self._c_node = plist_new_data(value, len(value)) + + def __repr__(self): + d = self.get_value() + return '' % d + + def __richcmp__(self, other, op): + cdef str d = self.get_value() + if op == 0: + return d < other + if op == 1: + return d <= other + if op == 2: + return d == other + if op == 3: + return d != other + if op == 4: + return d > other + if op == 5: + return d >= other + + cpdef bytes get_value(self): + cdef char* val = NULL + cdef uint64_t length = 0 + plist_get_data_val(self._c_node, &val, &length) + + return val[:length] + + cpdef set_value(self, bytes value): + plist_set_data_val(self._c_node, value, len(value)) + +cdef Data Data_factory(plist_t c_node, bool managed=True): + cdef Data instance = Data.__new__(Data) + instance._c_managed = managed + instance._c_node = c_node + return instance + +cdef plist_t create_dict_plist(value=None): + cdef plist_t node = NULL + cdef plist_t c_node = NULL + node = plist_new_dict() + if value is not None and isinstance(value, dict): + for key, item in value.items(): + c_node = native_to_plist_t(item) + plist_dict_insert_item(node, key, c_node) + c_node = NULL + return node + +cdef class Dict(Node): + def __cinit__(self, value=None, *args, **kwargs): + self._c_node = create_dict_plist(value) + + def __init__(self, value=None, *args, **kwargs): + self._init() + + cdef void _init(self): + cdef plist_dict_iter it = NULL + cdef char* key = NULL + cdef plist_t subnode = NULL + + self._map = {} + + plist_dict_new_iter(self._c_node, &it); + plist_dict_next_item(self._c_node, it, &key, &subnode); + + while subnode is not NULL: + self._map[key] = plist_t_to_node(subnode, False) + subnode = NULL + free(key) + key = NULL + plist_dict_next_item(self._c_node, it, &key, &subnode); + free(it) + + def __dealloc__(self): + self._map = None + Node.__dealloc__(self) + + def __richcmp__(self, other, op): + cdef dict d = self.get_value() + if op == 0: + return d < other + if op == 1: + return d <= other + if op == 2: + return d == other + if op == 3: + return d != other + if op == 4: + return d > other + if op == 5: + return d >= other + + def __len__(self): + return len(self._map) + + def __repr__(self): + return '' % self._map + + cpdef dict get_value(self): + return dict([(key, value.get_value()) for key, value in self.items()]) + + cpdef set_value(self, dict value): + plist_free(self._c_node) + self._map = {} + self._c_node = NULL + self._c_node = create_dict_plist(value) + self._init() + + def __iter__(self): + return self._map.__iter__() + + cpdef bool has_key(self, key): + return self._map.has_key(key) + + cpdef object get(self, key, default=None): + return self._map.get(key, default) + + cpdef list keys(self): + return self._map.keys() + + cpdef object iterkeys(self): + return self._map.iterkeys() + + cpdef list items(self): + return self._map.items() + + cpdef object iteritems(self): + return self._map.iteritems() + + cpdef list values(self): + return self._map.values() + + cpdef object itervalues(self): + return self._map.itervalues() + + def __getitem__(self, key): + return self._map[key] + + def __setitem__(self, key, value): + cdef Node n + if isinstance(value, Node): + n = value.copy() + else: + n = plist_t_to_node(native_to_plist_t(value), False) + + plist_dict_insert_item(self._c_node, key, n._c_node) + self._map[key] = n + + def __delitem__(self, key): + del self._map[key] + plist_dict_remove_item(self._c_node, key) + +cdef Dict Dict_factory(plist_t c_node, bool managed=True): + cdef Dict instance = Dict.__new__(Dict) + instance._c_managed = managed + instance._c_node = c_node + instance._init() + return instance + +cdef plist_t create_array_plist(value=None): + cdef plist_t node = NULL + cdef plist_t c_node = NULL + node = plist_new_array() + if value is not None and (isinstance(value, list) or isinstance(value, tuple)): + for item in value: + c_node = native_to_plist_t(item) + plist_array_append_item(node, c_node) + c_node = NULL + return node + +cdef class Array(Node): + def __cinit__(self, value=None, *args, **kwargs): + self._c_node = create_array_plist(value) + + def __init__(self, value=None, *args, **kwargs): + self._init() + + cdef void _init(self): + cdef uint32_t size = plist_array_get_size(self._c_node) + cdef plist_t subnode = NULL + + for i from 0 <= i < size: + subnode = plist_array_get_item(self._c_node, i) + self._array.append(plist_t_to_node(subnode, False)) + + def __richcmp__(self, other, op): + cdef list l = self.get_value() + if op == 0: + return l < other + if op == 1: + return l <= other + if op == 2: + return l == other + if op == 3: + return l != other + if op == 4: + return l > other + if op == 5: + return l >= other + + def __len__(self): + return len(self._array) + + def __repr__(self): + return '' % self._array + + cpdef list get_value(self): + return [i.get_value() for i in self] + + cpdef set_value(self, value): + self._array = [] + plist_free(self._c_node) + self._c_node = NULL + self._c_node = create_array_plist(value) + self._init() + + def __iter__(self): + return self._array.__iter__() + + def __getitem__(self, index): + return self._array[index] + + def __setitem__(self, index, value): + cdef Node n + if isinstance(value, Node): + n = value.copy() + else: + n = plist_t_to_node(native_to_plist_t(value), False) + + if index < 0: + index = len(self) + index + + plist_array_set_item(self._c_node, n._c_node, index) + self._array[index] = n + + def __delitem__(self, index): + if index < 0: + index = len(self) + index + del self._array[index] + plist_array_remove_item(self._c_node, index) + + cpdef append(self, item): + cdef Node n + + if isinstance(item, Node): + n = item.copy() + else: + n = plist_t_to_node(native_to_plist_t(item), False) + + plist_array_append_item(self._c_node, n._c_node) + self._array.append(n) + +cdef Array Array_factory(plist_t c_node, bool managed=True): + cdef Array instance = Array.__new__(Array) + instance._c_managed = managed + instance._c_node = c_node + instance._init() + return instance + +cpdef object from_xml(xml): + cdef plist_t c_node = NULL + plist_from_xml(xml, len(xml), &c_node) + return plist_t_to_node(c_node) + +cpdef object from_bin(bytes bin): + cdef plist_t c_node = NULL + plist_from_bin(bin, len(bin), &c_node) + return plist_t_to_node(c_node) + +cdef plist_t native_to_plist_t(object native): + cdef plist_t c_node + cdef plist_t child_c_node + cdef int32_t secs = 0 + cdef int32_t usecs = 0 + cdef Node node + if isinstance(native, Node): + node = native + return plist_copy(node._c_node) + if isinstance(native, basestring): + return plist_new_string(native) + if isinstance(native, bool): + return plist_new_bool(native) + if isinstance(native, int) or isinstance(native, long): + return plist_new_uint(native) + if isinstance(native, float): + return plist_new_real(native) + if isinstance(native, dict): + return create_dict_plist(native) + if isinstance(native, list) or isinstance(native, tuple): + return create_array_plist(native) + if check_datetime(native): + return create_date_plist(native) + +cdef object plist_t_to_node(plist_t c_plist, bool 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: + return Integer_factory(c_plist, managed) + if t == PLIST_REAL: + return Real_factory(c_plist, managed) + if t == PLIST_STRING: + return String_factory(c_plist, managed) + if t == PLIST_ARRAY: + return Array_factory(c_plist, managed) + if t == PLIST_DICT: + return Dict_factory(c_plist, managed) + if t == PLIST_DATE: + return Date_factory(c_plist, managed) + if t == PLIST_DATA: + return Data_factory(c_plist, managed) -- cgit v1.1-32-gdbae