From 36ad4384303e94b19cdf7a5ff43182efebe1b398 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 26 Sep 2011 17:01:47 +0200 Subject: [PATCH 01/12] Added .gitignore file --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..85f404f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.swp +build/* From 2ca52d65bb113e8639e732f67fec3c3223c0a444 Mon Sep 17 00:00:00 2001 From: Bryan Forbes Date: Mon, 26 Sep 2011 17:14:39 +0200 Subject: [PATCH 02/12] Added cython bindings. --- CMakeLists.txt | 17 +- cmake/modules/FindCython.cmake | 10 + cython/CMakeLists.txt | 30 ++ cython/plist.pxd | 62 +++ cython/plist.pyx | 699 +++++++++++++++++++++++++++++++++ cython/plist_util.c | 41 ++ cython/plist_util.h | 5 + 7 files changed, 861 insertions(+), 3 deletions(-) create mode 100644 cmake/modules/FindCython.cmake create mode 100644 cython/CMakeLists.txt create mode 100644 cython/plist.pxd create mode 100644 cython/plist.pyx create mode 100644 cython/plist_util.c create mode 100644 cython/plist_util.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a1d34e8..3ce3b7c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,13 +17,21 @@ ENDIF(NOT DEFINED CMAKE_INSTALL_LIBDIR) FIND_PACKAGE( LibXml2 REQUIRED ) -OPTION(ENABLE_PYTHON "Enable Python bindings (needs Swig)" ON) +OPTION(ENABLE_SWIG "Enable SWIG Python bindings (needs Swig)" ON) +OPTION(ENABLE_CYTHON "Enable Cython Python bindings (needs Cython)" ON) -IF(ENABLE_PYTHON) +IF(ENABLE_SWIG) FIND_PACKAGE( SWIG ) +ENDIF(ENABLE_SWIG) + +IF(ENABLE_CYTHON) + FIND_PACKAGE( Cython ) +ENDIF(ENABLE_CYTHON) + +IF(ENABLE_SWIG OR ENABLE_CYTHON) FIND_PACKAGE( PythonInterp ) FIND_PACKAGE( PythonLibs ) -ENDIF(ENABLE_PYTHON) +ENDIF(ENABLE_SWIG OR ENABLE_CYTHON) INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_INCLUDE_PATH}) @@ -52,6 +60,9 @@ ADD_SUBDIRECTORY( test ) IF ( SWIG_FOUND AND PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND ) ADD_SUBDIRECTORY( swig ) ENDIF ( SWIG_FOUND AND PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND ) +IF ( CYTHON_FOUND AND PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND ) + ADD_SUBDIRECTORY( cython ) +ENDIF ( CYTHON_FOUND AND PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND ) # add uninstall target CONFIGURE_FILE( "${CMAKE_SOURCE_DIR}/cmake/modules/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY) diff --git a/cmake/modules/FindCython.cmake b/cmake/modules/FindCython.cmake new file mode 100644 index 0000000..89005b7 --- /dev/null +++ b/cmake/modules/FindCython.cmake @@ -0,0 +1,10 @@ +FIND_PROGRAM(CYTHON_EXECUTABLE cython) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(Cython DEFAULT_MSG CYTHON_EXECUTABLE) + +MARK_AS_ADVANCED(CYTHON_EXECUTABLE) + +IF(CYTHON_FOUND) + SET(CYTHON_USE_FILE ${CMAKE_SOURCE_DIR}/cmake/modules/UseCython.cmake) +ENDIF(CYTHON_FOUND) diff --git a/cython/CMakeLists.txt b/cython/CMakeLists.txt new file mode 100644 index 0000000..eac6bee --- /dev/null +++ b/cython/CMakeLists.txt @@ -0,0 +1,30 @@ + +INCLUDE_DIRECTORIES( ${PYTHON_INCLUDE_PATH} ${CMAKE_CURRENT_SOURCE_DIR} ) + + +SET(plist_SRC + ${CMAKE_CURRENT_BINARY_DIR}/plist.c ) + +SET(plist_HDR + ${CMAKE_CURRENT_SOURCE_DIR}/plist.pxd ) + +ADD_CUSTOM_COMMAND( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/plist.c + COMMAND ${CYTHON_EXECUTABLE} -o ${CMAKE_CURRENT_BINARY_DIR}/plist.c ${CMAKE_CURRENT_SOURCE_DIR}/plist.pyx + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/plist.pyx ${CMAKE_CURRENT_SOURCE_DIR}/plist.pxd +) + + +EXEC_PROGRAM("${PYTHON_EXECUTABLE}" + ARGS "-c 'try:\n import distutils.sysconfig; print distutils.sysconfig.get_python_lib(1,0,\"${CMAKE_INSTALL_PREFIX}\")\nexcept: pass\n'" + OUTPUT_VARIABLE DISTUTILS_PYTHON_ILIBRARY_PATH + ) + +PYTHON_ADD_MODULE(cython_plist plist.c plist_util.c) +SET_TARGET_PROPERTIES(cython_plist PROPERTIES PREFIX "" OUTPUT_NAME plist) +TARGET_LINK_LIBRARIES(cython_plist plist ${PYTHON_LIBRARIES}) + +INSTALL( FILES ${CMAKE_CURRENT_BINARY_DIR}/plist${CMAKE_SHARED_MODULE_SUFFIX} + DESTINATION ${DISTUTILS_PYTHON_ILIBRARY_PATH} ) +INSTALL( FILES ${CMAKE_CURRENT_SOURCE_DIR}/plist.pxd + DESTINATION include/plist/cython COMPONENT dev) diff --git a/cython/plist.pxd b/cython/plist.pxd new file mode 100644 index 0000000..daafd78 --- /dev/null +++ b/cython/plist.pxd @@ -0,0 +1,62 @@ +cdef extern from "plist/plist.h": + ctypedef void *plist_t + ctypedef void *plist_dict_iter + +cdef class Node: + cdef plist_t _c_node + cdef bool _c_managed + cpdef object __deepcopy__(self, memo=*) + cpdef bytes to_xml(self) + cpdef bytes to_bin(self) + cpdef object copy(self) + +cdef class Bool(Node): + cpdef set_value(self, value) + cpdef bool get_value(self) + +cdef class Integer(Node): + cpdef set_value(self, value) + cpdef int get_value(self) + +cdef class Real(Node): + cpdef set_value(self, value) + cpdef float get_value(self) + +cdef class String(Node): + cpdef set_value(self, unicode value) + cpdef unicode get_value(self) + +cdef class Date(Node): + cpdef set_value(self, value) + cpdef object get_value(self) + +cdef class Data(Node): + cpdef set_value(self, bytes value) + cpdef bytes get_value(self) + +cdef class Dict(Node): + cdef dict _map + cdef void _init(self) + cpdef set_value(self, dict value) + cpdef dict get_value(self) + cpdef bool has_key(self, key) + cpdef object get(self, key, default=*) + cpdef list keys(self) + cpdef list items(self) + cpdef list values(self) + cpdef object iterkeys(self) + cpdef object iteritems(self) + cpdef object itervalues(self) + +cdef class Array(Node): + cdef list _array + cdef void _init(self) + cpdef set_value(self, value) + cpdef list get_value(self) + cpdef append(self, item) + +cpdef object from_xml(xml) +cpdef object from_bin(bytes bin) + +cdef object plist_t_to_node(plist_t c_plist, bool managed=*) +cdef plist_t native_to_plist_t(object native) 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) diff --git a/cython/plist_util.c b/cython/plist_util.c new file mode 100644 index 0000000..70c5be3 --- /dev/null +++ b/cython/plist_util.c @@ -0,0 +1,41 @@ +#include "plist_util.h" + +#include +#include + +void datetime_to_ints(PyObject* obj, int32_t* sec, int32_t* usec) { + PyDateTime_IMPORT; + if (!PyDateTime_Check(obj)) { + PyErr_SetString(PyExc_ValueError,"Expected a datetime"); + sec = NULL; + usec = NULL; + return; + } + struct tm t = { + PyDateTime_DATE_GET_SECOND(obj), + PyDateTime_DATE_GET_MINUTE(obj), + PyDateTime_DATE_GET_HOUR(obj), + PyDateTime_GET_DAY(obj), + PyDateTime_GET_MONTH(obj)-1, + PyDateTime_GET_YEAR(obj)-1900, + 0,0,0 + }; + *sec = (int32_t)mktime(&t); + *usec = PyDateTime_DATE_GET_MICROSECOND(obj); +} +PyObject* ints_to_datetime(int32_t sec, int32_t usec) { + time_t sec_tt = sec; + struct tm* t = gmtime(&sec_tt); + if(t){ + PyDateTime_IMPORT; + return PyDateTime_FromDateAndTime(t->tm_year+1900, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, usec); + } + return NULL; +} +int check_datetime(PyObject* ob) { + if(ob){ + PyDateTime_IMPORT; + return PyDateTime_Check(ob); + } + return 0; +} diff --git a/cython/plist_util.h b/cython/plist_util.h new file mode 100644 index 0000000..fbf56b6 --- /dev/null +++ b/cython/plist_util.h @@ -0,0 +1,5 @@ +#include + +void datetime_to_ints(PyObject* obj, int32_t* sec, int32_t* usec); +PyObject* ints_to_datetime(int32_t sec, int32_t usec); +int check_datetime(PyObject* obj); From f57dd030b971d14942aaec3a42d176d57547355c Mon Sep 17 00:00:00 2001 From: Bryan Forbes Date: Mon, 26 Sep 2011 17:15:33 +0200 Subject: [PATCH 03/12] Removed a call to __dealloc__ and added initialization of _array. --- cython/plist.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cython/plist.pyx b/cython/plist.pyx index a1282e7..336b16f 100644 --- a/cython/plist.pyx +++ b/cython/plist.pyx @@ -461,7 +461,6 @@ cdef class Dict(Node): def __dealloc__(self): self._map = None - Node.__dealloc__(self) def __richcmp__(self, other, op): cdef dict d = self.get_value() @@ -564,6 +563,7 @@ cdef class Array(Node): self._init() cdef void _init(self): + self._array = [] cdef uint32_t size = plist_array_get_size(self._c_node) cdef plist_t subnode = NULL From 3ceae531d868f6c1341cf916bcb0ae1248d688cd Mon Sep 17 00:00:00 2001 From: Bryan Forbes Date: Mon, 26 Sep 2011 17:16:13 +0200 Subject: [PATCH 04/12] If the plist type is none, return None. --- cython/plist.pyx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cython/plist.pyx b/cython/plist.pyx index 336b16f..f4e7dbb 100644 --- a/cython/plist.pyx +++ b/cython/plist.pyx @@ -697,3 +697,5 @@ cdef object plist_t_to_node(plist_t c_plist, bool managed=True): return Date_factory(c_plist, managed) if t == PLIST_DATA: return Data_factory(c_plist, managed) + if t == PLIST_NONE: + return None From 89900d6decbfe805720a9cbce65655ec31086f94 Mon Sep 17 00:00:00 2001 From: Bryan Forbes Date: Mon, 26 Sep 2011 17:16:51 +0200 Subject: [PATCH 05/12] Fixed some memory leaks and unicode handling. --- cython/plist.pxd | 9 ++-- cython/plist.pyx | 106 ++++++++++++++++++++++++++++++----------------- 2 files changed, 72 insertions(+), 43 deletions(-) diff --git a/cython/plist.pxd b/cython/plist.pxd index daafd78..6a96817 100644 --- a/cython/plist.pxd +++ b/cython/plist.pxd @@ -1,25 +1,26 @@ cdef extern from "plist/plist.h": ctypedef void *plist_t ctypedef void *plist_dict_iter + void plist_free(plist_t node) cdef class Node: cdef plist_t _c_node cdef bool _c_managed cpdef object __deepcopy__(self, memo=*) - cpdef bytes to_xml(self) + cpdef unicode to_xml(self) cpdef bytes to_bin(self) cpdef object copy(self) cdef class Bool(Node): - cpdef set_value(self, value) + cpdef set_value(self, object value) cpdef bool get_value(self) cdef class Integer(Node): - cpdef set_value(self, value) + cpdef set_value(self, object value) cpdef int get_value(self) cdef class Real(Node): - cpdef set_value(self, value) + cpdef set_value(self, object value) cpdef float get_value(self) cdef class String(Node): diff --git a/cython/plist.pyx b/cython/plist.pyx index f4e7dbb..c636f7d 100644 --- a/cython/plist.pyx +++ b/cython/plist.pyx @@ -10,6 +10,8 @@ ELSE: ctypedef unsigned long long int uint64_t cimport python_unicode +cimport python_string +cimport stdlib cdef extern from *: ctypedef enum plist_type: @@ -80,9 +82,6 @@ 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) -cdef extern from *: - void free(void *ptr) - cdef class Node: def __init__(self, *args, **kwargs): self._c_managed = True @@ -99,19 +98,27 @@ cdef class Node: 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 + cpdef unicode to_xml(self): + cdef: + char* out = NULL + uint32_t length plist_to_xml(self._c_node, &out, &length) - return out[:length] + try: + return python_unicode.PyUnicode_DecodeUTF8(out, length, 'strict') + finally: + stdlib.free(out) cpdef bytes to_bin(self): - cdef char* out = NULL - cdef uint32_t length + cdef: + char* out = NULL + uint32_t length plist_to_bin(self._c_node, &out, &length) - return out[:length] + try: + return python_string.PyString_FromStringAndSize(out, length) + finally: + stdlib.free(out) property parent: def __get__(self): @@ -156,7 +163,7 @@ cdef class Bool(Node): b = self.get_value() return '' % b - cpdef set_value(self, value): + cpdef set_value(self, object value): plist_set_bool_val(self._c_node, bool(value)) cpdef bool get_value(self): @@ -178,7 +185,7 @@ cdef class Integer(Node): self._c_node = plist_new_uint(int(value)) def __repr__(self): - i = self.get_value() + cdef int i = self.get_value() return '' % i def __int__(self): @@ -202,7 +209,7 @@ cdef class Integer(Node): if op == 5: return i >= other - cpdef set_value(self, value): + cpdef set_value(self, object value): plist_set_uint_val(self._c_node, int(value)) cpdef int get_value(self): @@ -248,7 +255,7 @@ cdef class Real(Node): if op == 5: return f >= other - cpdef set_value(self, value): + cpdef set_value(self, object value): plist_set_real_val(self._c_node, float(value)) cpdef float get_value(self): @@ -266,24 +273,28 @@ from python_version cimport PY_MAJOR_VERSION cdef class String(Node): def __cinit__(self, value=None, *args, **kwargs): + cdef: + char* c_utf8_data = NULL + bytes utf8_data 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 + value.decode('ascii') # trial decode + utf8_data = value.decode('ascii') else: raise ValueError("requires text input, got %s" % type(value)) - self._c_node = plist_new_string(utf8_data) + c_utf8_data = utf8_data + self._c_node = plist_new_string(c_utf8_data) def __repr__(self): s = self.get_value() - return '' % s + return '' % s.encode('utf-8') def __richcmp__(self, other, op): - cdef str s = self.get_value() + cdef unicode s = self.get_value() if op == 0: return s < other if op == 1: @@ -298,22 +309,30 @@ cdef class String(Node): return s >= other cpdef set_value(self, unicode value): + cdef: + char* c_utf8_data = NULL + bytes utf8_data if value is None: - self._c_node = plist_new_string("") + plist_set_string_val(self._c_node, c_utf8_data) 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 + value.decode('ascii') # trial decode + utf8_data = value.decode('ascii') else: raise ValueError("requires text input, got %s" % type(value)) - self._c_node = plist_new_string(utf8_data) + c_utf8_data = utf8_data + plist_set_string_val(self._c_node, c_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: + char* c_value = NULL + plist_get_string_val(self._c_node, &c_value) + try: + return python_unicode.PyUnicode_DecodeUTF8(c_value, stdlib.strlen(c_value), 'strict') + finally: + stdlib.free(c_value) cdef String String_factory(plist_t c_node, bool managed=True): cdef String instance = String.__new__(String) @@ -393,7 +412,7 @@ cdef class Data(Node): return '' % d def __richcmp__(self, other, op): - cdef str d = self.get_value() + cdef bytes d = self.get_value() if op == 0: return d < other if op == 1: @@ -408,11 +427,15 @@ cdef class Data(Node): return d >= other cpdef bytes get_value(self): - cdef char* val = NULL - cdef uint64_t length = 0 + cdef: + char* val = NULL + uint64_t length = 0 plist_get_data_val(self._c_node, &val, &length) - return val[:length] + try: + return python_string.PyString_FromStringAndSize(val, length) + finally: + stdlib.free(val) cpdef set_value(self, bytes value): plist_set_data_val(self._c_node, value, len(value)) @@ -434,6 +457,8 @@ cdef plist_t create_dict_plist(value=None): c_node = NULL return node +cimport python_dict + cdef class Dict(Node): def __cinit__(self, value=None, *args, **kwargs): self._c_node = create_dict_plist(value) @@ -446,18 +471,18 @@ cdef class Dict(Node): cdef char* key = NULL cdef plist_t subnode = NULL - self._map = {} + self._map = python_dict.PyDict_New() 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) + python_dict.PyDict_SetItem(self._map, key, plist_t_to_node(subnode, False)) subnode = NULL - free(key) + stdlib.free(key) key = NULL plist_dict_next_item(self._c_node, it, &key, &subnode); - free(it) + stdlib.free(it) def __dealloc__(self): self._map = None @@ -478,13 +503,15 @@ cdef class Dict(Node): return d >= other def __len__(self): - return len(self._map) + return python_dict.PyDict_Size(self._map) def __repr__(self): return '' % self._map cpdef dict get_value(self): + cdef dict result = python_dict.PyDict_New() return dict([(key, value.get_value()) for key, value in self.items()]) + return result cpdef set_value(self, dict value): plist_free(self._c_node) @@ -503,18 +530,19 @@ cdef class Dict(Node): return self._map.get(key, default) cpdef list keys(self): - return self._map.keys() + return python_dict.PyDict_Keys(self._map) cpdef object iterkeys(self): return self._map.iterkeys() cpdef list items(self): - return self._map.items() + return python_dict.PyDict_Items(self._map) cpdef object iteritems(self): return self._map.iteritems() cpdef list values(self): + return python_dict.PyDict_Values(self._map) return self._map.values() cpdef object itervalues(self): @@ -534,7 +562,7 @@ cdef class Dict(Node): self._map[key] = n def __delitem__(self, key): - del self._map[key] + python_dict.PyDict_DelItem(self._map, key) plist_dict_remove_item(self._c_node, key) cdef Dict Dict_factory(plist_t c_node, bool managed=True): @@ -667,7 +695,7 @@ cdef plist_t native_to_plist_t(object native): if isinstance(native, basestring): return plist_new_string(native) if isinstance(native, bool): - return plist_new_bool(native) + return plist_new_bool(native) if isinstance(native, int) or isinstance(native, long): return plist_new_uint(native) if isinstance(native, float): From bf1dcaecc3e7c4a123059ff5347bc5180835dbad Mon Sep 17 00:00:00 2001 From: Bryan Forbes Date: Mon, 26 Sep 2011 17:17:22 +0200 Subject: [PATCH 06/12] Changed bool to bint in Cython functions. Added some more type qualifiers. --- cython/plist.pxd | 4 ++-- cython/plist.pyx | 28 ++++++++++++++-------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/cython/plist.pxd b/cython/plist.pxd index 6a96817..7cff51c 100644 --- a/cython/plist.pxd +++ b/cython/plist.pxd @@ -5,7 +5,7 @@ cdef extern from "plist/plist.h": cdef class Node: cdef plist_t _c_node - cdef bool _c_managed + cdef bint _c_managed cpdef object __deepcopy__(self, memo=*) cpdef unicode to_xml(self) cpdef bytes to_bin(self) @@ -59,5 +59,5 @@ cdef class Array(Node): cpdef object from_xml(xml) cpdef object from_bin(bytes bin) -cdef object plist_t_to_node(plist_t c_plist, bool managed=*) +cdef object plist_t_to_node(plist_t c_plist, bint managed=*) cdef plist_t native_to_plist_t(object native) diff --git a/cython/plist.pyx b/cython/plist.pyx index c636f7d..aa4f0d8 100644 --- a/cython/plist.pyx +++ b/cython/plist.pyx @@ -171,7 +171,7 @@ cdef class Bool(Node): plist_get_bool_val(self._c_node, &value) return bool(value) -cdef Bool Bool_factory(plist_t c_node, bool managed=True): +cdef Bool Bool_factory(plist_t c_node, bint managed=True): cdef Bool instance = Bool.__new__(Bool) instance._c_managed = managed instance._c_node = c_node @@ -217,7 +217,7 @@ cdef class Integer(Node): plist_get_uint_val(self._c_node, &value) return value -cdef Integer Integer_factory(plist_t c_node, bool managed=True): +cdef Integer Integer_factory(plist_t c_node, bint managed=True): cdef Integer instance = Integer.__new__(Integer) instance._c_managed = managed instance._c_node = c_node @@ -263,7 +263,7 @@ cdef class Real(Node): plist_get_real_val(self._c_node, &value) return value -cdef Real Real_factory(plist_t c_node, bool managed=True): +cdef Real Real_factory(plist_t c_node, bint managed=True): cdef Real instance = Real.__new__(Real) instance._c_managed = managed instance._c_node = c_node @@ -285,7 +285,7 @@ cdef class String(Node): value.decode('ascii') # trial decode utf8_data = value.decode('ascii') else: - raise ValueError("requires text input, got %s" % type(value)) + raise ValueError("Requires unicode input, got %s" % type(value)) c_utf8_data = utf8_data self._c_node = plist_new_string(c_utf8_data) @@ -321,7 +321,7 @@ cdef class String(Node): value.decode('ascii') # trial decode utf8_data = value.decode('ascii') else: - raise ValueError("requires text input, got %s" % type(value)) + raise ValueError("Requires unicode input, got %s" % type(value)) c_utf8_data = utf8_data plist_set_string_val(self._c_node, c_utf8_data) @@ -334,7 +334,7 @@ cdef class String(Node): finally: stdlib.free(c_value) -cdef String String_factory(plist_t c_node, bool managed=True): +cdef String String_factory(plist_t c_node, bint managed=True): cdef String instance = String.__new__(String) instance._c_managed = managed instance._c_node = c_node @@ -386,7 +386,7 @@ cdef class Date(Node): plist_get_date_val(self._c_node, &secs, &usecs) return ints_to_datetime(secs, usecs) - cpdef set_value(self, value): + cpdef set_value(self, object value): cdef int32_t secs cdef int32_t usecs if not check_datetime(value): @@ -394,7 +394,7 @@ cdef class Date(Node): 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 Date_factory(plist_t c_node, bint managed=True): cdef Date instance = Date.__new__(Date) instance._c_managed = managed instance._c_node = c_node @@ -440,13 +440,13 @@ cdef class Data(Node): 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 Data_factory(plist_t c_node, bint 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 create_dict_plist(object value=None): cdef plist_t node = NULL cdef plist_t c_node = NULL node = plist_new_dict() @@ -565,14 +565,14 @@ cdef class Dict(Node): python_dict.PyDict_DelItem(self._map, key) plist_dict_remove_item(self._c_node, key) -cdef Dict Dict_factory(plist_t c_node, bool managed=True): +cdef Dict Dict_factory(plist_t c_node, bint 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 create_array_plist(object value=None): cdef plist_t node = NULL cdef plist_t c_node = NULL node = plist_new_array() @@ -666,7 +666,7 @@ cdef class Array(Node): 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 Array_factory(plist_t c_node, bint managed=True): cdef Array instance = Array.__new__(Array) instance._c_managed = managed instance._c_node = c_node @@ -707,7 +707,7 @@ cdef plist_t native_to_plist_t(object native): if check_datetime(native): return create_date_plist(native) -cdef object plist_t_to_node(plist_t c_plist, bool managed=True): +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) From b1ad30f5bf9c5067d1bdb5d7a5f9e62e9db5a137 Mon Sep 17 00:00:00 2001 From: Bryan Forbes Date: Mon, 26 Sep 2011 17:18:01 +0200 Subject: [PATCH 07/12] More qualifiers. --- cython/plist.pxd | 8 ++++---- cython/plist.pyx | 34 +++++++++++++++++++--------------- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/cython/plist.pxd b/cython/plist.pxd index 7cff51c..81a272e 100644 --- a/cython/plist.pxd +++ b/cython/plist.pxd @@ -24,15 +24,15 @@ cdef class Real(Node): cpdef float get_value(self) cdef class String(Node): - cpdef set_value(self, unicode value) + cpdef set_value(self, object value) cpdef unicode get_value(self) cdef class Date(Node): - cpdef set_value(self, value) + cpdef set_value(self, object value) cpdef object get_value(self) cdef class Data(Node): - cpdef set_value(self, bytes value) + cpdef set_value(self, object value) cpdef bytes get_value(self) cdef class Dict(Node): @@ -54,7 +54,7 @@ cdef class Array(Node): cdef void _init(self) cpdef set_value(self, value) cpdef list get_value(self) - cpdef append(self, item) + cpdef append(self, object item) cpdef object from_xml(xml) cpdef object from_bin(bytes bin) diff --git a/cython/plist.pyx b/cython/plist.pyx index aa4f0d8..5a305c4 100644 --- a/cython/plist.pyx +++ b/cython/plist.pyx @@ -107,7 +107,8 @@ cdef class Node: try: return python_unicode.PyUnicode_DecodeUTF8(out, length, 'strict') finally: - stdlib.free(out) + if out != NULL: + stdlib.free(out) cpdef bytes to_bin(self): cdef: @@ -118,7 +119,8 @@ cdef class Node: try: return python_string.PyString_FromStringAndSize(out, length) finally: - stdlib.free(out) + if out != NULL: + stdlib.free(out) property parent: def __get__(self): @@ -135,7 +137,7 @@ cdef class Node: return str(self.get_value()) cdef class Bool(Node): - def __cinit__(self, value=None, *args, **kwargs): + def __cinit__(self, object value=None, *args, **kwargs): if value is None: self._c_node = plist_new_bool(0) else: @@ -178,7 +180,7 @@ cdef Bool Bool_factory(plist_t c_node, bint managed=True): return instance cdef class Integer(Node): - def __cinit__(self, value=None, *args, **kwargs): + def __cinit__(self, object value=None, *args, **kwargs): if value is None: self._c_node = plist_new_uint(0) else: @@ -224,7 +226,7 @@ cdef Integer Integer_factory(plist_t c_node, bint managed=True): return instance cdef class Real(Node): - def __cinit__(self, value=None, *args, **kwargs): + def __cinit__(self, object value=None, *args, **kwargs): if value is None: self._c_node = plist_new_real(0.0) else: @@ -272,7 +274,7 @@ cdef Real Real_factory(plist_t c_node, bint managed=True): from python_version cimport PY_MAJOR_VERSION cdef class String(Node): - def __cinit__(self, value=None, *args, **kwargs): + def __cinit__(self, object value=None, *args, **kwargs): cdef: char* c_utf8_data = NULL bytes utf8_data @@ -308,7 +310,7 @@ cdef class String(Node): if op == 5: return s >= other - cpdef set_value(self, unicode value): + cpdef set_value(self, object value): cdef: char* c_utf8_data = NULL bytes utf8_data @@ -357,7 +359,7 @@ cdef plist_t create_date_plist(value=None): return node cdef class Date(Node): - def __cinit__(self, value=None, *args, **kwargs): + def __cinit__(self, object value=None, *args, **kwargs): self._c_node = create_date_plist(value) def __repr__(self): @@ -401,7 +403,7 @@ cdef Date Date_factory(plist_t c_node, bint managed=True): return instance cdef class Data(Node): - def __cinit__(self, value=None, *args, **kwargs): + def __cinit__(self, object value=None, *args, **kwargs): if value is None: self._c_node = plist_new_data(NULL, 0) else: @@ -437,8 +439,10 @@ cdef class Data(Node): finally: stdlib.free(val) - cpdef set_value(self, bytes value): - plist_set_data_val(self._c_node, value, len(value)) + cpdef set_value(self, object value): + cdef: + bytes py_val = value + plist_set_data_val(self._c_node, py_val, len(value)) cdef Data Data_factory(plist_t c_node, bint managed=True): cdef Data instance = Data.__new__(Data) @@ -460,7 +464,7 @@ cdef plist_t create_dict_plist(object value=None): cimport python_dict cdef class Dict(Node): - def __cinit__(self, value=None, *args, **kwargs): + def __cinit__(self, object value=None, *args, **kwargs): self._c_node = create_dict_plist(value) def __init__(self, value=None, *args, **kwargs): @@ -584,7 +588,7 @@ cdef plist_t create_array_plist(object value=None): return node cdef class Array(Node): - def __cinit__(self, value=None, *args, **kwargs): + def __cinit__(self, object value=None, *args, **kwargs): self._c_node = create_array_plist(value) def __init__(self, value=None, *args, **kwargs): @@ -623,7 +627,7 @@ cdef class Array(Node): cpdef list get_value(self): return [i.get_value() for i in self] - cpdef set_value(self, value): + cpdef set_value(self, object value): self._array = [] plist_free(self._c_node) self._c_node = NULL @@ -655,7 +659,7 @@ cdef class Array(Node): del self._array[index] plist_array_remove_item(self._c_node, index) - cpdef append(self, item): + cpdef append(self, object item): cdef Node n if isinstance(item, Node): From da9f709fadbcb63bc8f6b2dd4d917d920af3fe42 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 26 Sep 2011 17:34:53 +0200 Subject: [PATCH 08/12] cython: use bint instead of bool, fix deprecated stuff --- cython/plist.pxd | 4 ++-- cython/plist.pyx | 51 ++++++++++++++++++++++++------------------------ 2 files changed, 27 insertions(+), 28 deletions(-) diff --git a/cython/plist.pxd b/cython/plist.pxd index 81a272e..a31419d 100644 --- a/cython/plist.pxd +++ b/cython/plist.pxd @@ -13,7 +13,7 @@ cdef class Node: cdef class Bool(Node): cpdef set_value(self, object value) - cpdef bool get_value(self) + cpdef bint get_value(self) cdef class Integer(Node): cpdef set_value(self, object value) @@ -40,7 +40,7 @@ cdef class Dict(Node): cdef void _init(self) cpdef set_value(self, dict value) cpdef dict get_value(self) - cpdef bool has_key(self, key) + cpdef bint has_key(self, key) cpdef object get(self, key, default=*) cpdef list keys(self) cpdef list items(self) diff --git a/cython/plist.pyx b/cython/plist.pyx index 5a305c4..4732d0f 100644 --- a/cython/plist.pyx +++ b/cython/plist.pyx @@ -9,9 +9,8 @@ IF UNAME_MACHINE == 'x86_64': ELSE: ctypedef unsigned long long int uint64_t -cimport python_unicode -cimport python_string -cimport stdlib +cimport cpython +cimport libc.stdlib cdef extern from *: ctypedef enum plist_type: @@ -105,10 +104,10 @@ cdef class Node: plist_to_xml(self._c_node, &out, &length) try: - return python_unicode.PyUnicode_DecodeUTF8(out, length, 'strict') + return cpython.PyUnicode_DecodeUTF8(out, length, 'strict') finally: if out != NULL: - stdlib.free(out) + libc.stdlib.free(out) cpdef bytes to_bin(self): cdef: @@ -117,10 +116,10 @@ cdef class Node: plist_to_bin(self._c_node, &out, &length) try: - return python_string.PyString_FromStringAndSize(out, length) + return cpython.PyString_FromStringAndSize(out, length) finally: if out != NULL: - stdlib.free(out) + libc.stdlib.free(out) property parent: def __get__(self): @@ -147,7 +146,7 @@ cdef class Bool(Node): return self.get_value() def __richcmp__(self, other, op): - cdef bool b = self.get_value() + cdef bint b = self.get_value() if op == 0: return b < other if op == 1: @@ -168,7 +167,7 @@ cdef class Bool(Node): cpdef set_value(self, object value): plist_set_bool_val(self._c_node, bool(value)) - cpdef bool get_value(self): + cpdef bint get_value(self): cdef uint8_t value plist_get_bool_val(self._c_node, &value) return bool(value) @@ -271,7 +270,7 @@ cdef Real Real_factory(plist_t c_node, bint managed=True): instance._c_node = c_node return instance -from python_version cimport PY_MAJOR_VERSION +from cpython cimport PY_MAJOR_VERSION cdef class String(Node): def __cinit__(self, object value=None, *args, **kwargs): @@ -332,9 +331,9 @@ cdef class String(Node): char* c_value = NULL plist_get_string_val(self._c_node, &c_value) try: - return python_unicode.PyUnicode_DecodeUTF8(c_value, stdlib.strlen(c_value), 'strict') + return cpython.PyUnicode_DecodeUTF8(c_value, libc.stdlib.strlen(c_value), 'strict') finally: - stdlib.free(c_value) + libc.stdlib.free(c_value) cdef String String_factory(plist_t c_node, bint managed=True): cdef String instance = String.__new__(String) @@ -435,9 +434,9 @@ cdef class Data(Node): plist_get_data_val(self._c_node, &val, &length) try: - return python_string.PyString_FromStringAndSize(val, length) + return cpython.PyString_FromStringAndSize(val, length) finally: - stdlib.free(val) + libc.stdlib.free(val) cpdef set_value(self, object value): cdef: @@ -461,7 +460,7 @@ cdef plist_t create_dict_plist(object value=None): c_node = NULL return node -cimport python_dict +cimport cpython cdef class Dict(Node): def __cinit__(self, object value=None, *args, **kwargs): @@ -475,18 +474,18 @@ cdef class Dict(Node): cdef char* key = NULL cdef plist_t subnode = NULL - self._map = python_dict.PyDict_New() + self._map = cpython.PyDict_New() plist_dict_new_iter(self._c_node, &it); plist_dict_next_item(self._c_node, it, &key, &subnode); while subnode is not NULL: - python_dict.PyDict_SetItem(self._map, key, plist_t_to_node(subnode, False)) + cpython.PyDict_SetItem(self._map, key, plist_t_to_node(subnode, False)) subnode = NULL - stdlib.free(key) + libc.stdlib.free(key) key = NULL plist_dict_next_item(self._c_node, it, &key, &subnode); - stdlib.free(it) + libc.stdlib.free(it) def __dealloc__(self): self._map = None @@ -507,13 +506,13 @@ cdef class Dict(Node): return d >= other def __len__(self): - return python_dict.PyDict_Size(self._map) + return cpython.PyDict_Size(self._map) def __repr__(self): return '' % self._map cpdef dict get_value(self): - cdef dict result = python_dict.PyDict_New() + cdef dict result = cpython.PyDict_New() return dict([(key, value.get_value()) for key, value in self.items()]) return result @@ -527,26 +526,26 @@ cdef class Dict(Node): def __iter__(self): return self._map.__iter__() - cpdef bool has_key(self, key): + cpdef bint 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 python_dict.PyDict_Keys(self._map) + return cpython.PyDict_Keys(self._map) cpdef object iterkeys(self): return self._map.iterkeys() cpdef list items(self): - return python_dict.PyDict_Items(self._map) + return cpython.PyDict_Items(self._map) cpdef object iteritems(self): return self._map.iteritems() cpdef list values(self): - return python_dict.PyDict_Values(self._map) + return cpython.PyDict_Values(self._map) return self._map.values() cpdef object itervalues(self): @@ -566,7 +565,7 @@ cdef class Dict(Node): self._map[key] = n def __delitem__(self, key): - python_dict.PyDict_DelItem(self._map, key) + cpython.PyDict_DelItem(self._map, key) plist_dict_remove_item(self._c_node, key) cdef Dict Dict_factory(plist_t c_node, bint managed=True): From 567a749696a4a01d1eccc01e61dd2b1d76c39b5a Mon Sep 17 00:00:00 2001 From: Glenn Washburn Date: Mon, 26 Sep 2011 17:50:45 +0200 Subject: [PATCH 09/12] Allow swig typemap to recognize any std::vector as a python string. --- swig/plist.i | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/swig/plist.i b/swig/plist.i index 172a330..7755cc5 100644 --- a/swig/plist.i +++ b/swig/plist.i @@ -11,15 +11,15 @@ %include "stdint.i" %typemap(out) std::vector { - $result = SWIG_FromCharPtrAndSize((const char*)&($1[0]),(int)($1.size())); + $result = SWIG_FromCharPtrAndSize((const char*)&($1[0]),(size_t)($1.size())); } -%typemap(in) (const std::vector& v) +%typemap(in) (const std::vector&) { char* buffer = NULL; - int length = 0; + size_t length = 0; SWIG_AsCharPtrAndSize($input, &buffer, &length, NULL); - $1 = std::vector(buffer, buffer + length); + $1 = new std::vector(buffer, buffer + length - 1); } #if SWIGPYTHON From ed4c858c5f37113f498fe6e85366ae38a0f29a9d Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 11 Jan 2012 15:26:44 +0100 Subject: [PATCH 10/12] node_list: Fix memory corruption The corruption occured if you removed the last node from the list and later add a new node to the list. --- libcnary/node_list.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/libcnary/node_list.c b/libcnary/node_list.c index 2a9cf90..78f450e 100644 --- a/libcnary/node_list.c +++ b/libcnary/node_list.c @@ -59,7 +59,10 @@ int node_list_add(node_list_t* list, node_t* node) { node->prev = last; // Set the next element of our old "last" element - last->next = node; + if (last) { + // but only if the node list is not empty + last->next = node; + } // Set the lists prev to the new last element list->end = node; @@ -129,6 +132,9 @@ int node_list_remove(node_list_t* list, node_t* node) { node->prev->next = newnode; if (newnode) { newnode->prev = node->prev; + } else { + // last element in the list + list->end = node->prev; } } else { // we just removed the first element From 51303322d518f77f886da4ab6ba00adb5a336488 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 11 Jan 2012 15:27:09 +0100 Subject: [PATCH 11/12] Update NEWS for release --- NEWS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/NEWS b/NEWS index dc4a2bc..f9aa18c 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,11 @@ +Version 1.8 +~~~~~~~~~~~ + +- Changes: + * Add cython bindings + * Fix error in swig bindings + * Fix memory corruption in libcnary + Version 1.7 ~~~~~~~~~~~ From fd1dd885e29f6ba45dfd90575a210fd4139ec45c Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 11 Jan 2012 15:29:30 +0100 Subject: [PATCH 12/12] Bump version to 1.8 for release --- CMakeLists.txt | 2 +- doxygen.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ce3b7c..0bad840 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ PROJECT( libplist ) SET( LIBPLIST_VERSION_MAJOR "1" ) -SET( LIBPLIST_VERSION_MINOR "7" ) +SET( LIBPLIST_VERSION_MINOR "8" ) SET( LIBPLIST_SOVERSION "1" ) SET( LIBPLIST_VERSION "${LIBPLIST_VERSION_MAJOR}.${LIBPLIST_VERSION_MINOR}" ) SET( LIBPLIST_LIBVERSION "${LIBPLIST_SOVERSION}.${LIBPLIST_VERSION}" ) diff --git a/doxygen.cfg b/doxygen.cfg index dcda9d5..a77c3cd 100644 --- a/doxygen.cfg +++ b/doxygen.cfg @@ -31,7 +31,7 @@ PROJECT_NAME = libplist # This could be handy for archiving the generated documentation or # if some version control system is used. -PROJECT_NUMBER = 1.5 +PROJECT_NUMBER = 1.8 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put.