summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt17
-rw-r--r--cmake/modules/FindCython.cmake10
-rw-r--r--cython/CMakeLists.txt30
-rw-r--r--cython/plist.pxd62
-rw-r--r--cython/plist.pyx699
-rw-r--r--cython/plist_util.c41
-rw-r--r--cython/plist_util.h5
7 files changed, 861 insertions, 3 deletions
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 '<Bool: %s>' % 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 '<Integer: %s>' % 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 '<Real: %s>' % 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 '<String: %s>' % 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 '<Date: %s>' % 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 '<Data: %s>' % 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 '<Dict: %s>' % 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 '<Array: %s>' % 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 <time.h>
+#include <datetime.h>
+
+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 <Python.h>
+
+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);