diff options
| -rw-r--r-- | CMakeLists.txt | 17 | ||||
| -rw-r--r-- | cmake/modules/FindCython.cmake | 10 | ||||
| -rw-r--r-- | cython/CMakeLists.txt | 30 | ||||
| -rw-r--r-- | cython/plist.pxd | 62 | ||||
| -rw-r--r-- | cython/plist.pyx | 699 | ||||
| -rw-r--r-- | cython/plist_util.c | 41 | ||||
| -rw-r--r-- | cython/plist_util.h | 5 |
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) | |||
| 17 | 17 | ||
| 18 | FIND_PACKAGE( LibXml2 REQUIRED ) | 18 | FIND_PACKAGE( LibXml2 REQUIRED ) |
| 19 | 19 | ||
| 20 | OPTION(ENABLE_PYTHON "Enable Python bindings (needs Swig)" ON) | 20 | OPTION(ENABLE_SWIG "Enable SWIG Python bindings (needs Swig)" ON) |
| 21 | OPTION(ENABLE_CYTHON "Enable Cython Python bindings (needs Cython)" ON) | ||
| 21 | 22 | ||
| 22 | IF(ENABLE_PYTHON) | 23 | IF(ENABLE_SWIG) |
| 23 | FIND_PACKAGE( SWIG ) | 24 | FIND_PACKAGE( SWIG ) |
| 25 | ENDIF(ENABLE_SWIG) | ||
| 26 | |||
| 27 | IF(ENABLE_CYTHON) | ||
| 28 | FIND_PACKAGE( Cython ) | ||
| 29 | ENDIF(ENABLE_CYTHON) | ||
| 30 | |||
| 31 | IF(ENABLE_SWIG OR ENABLE_CYTHON) | ||
| 24 | FIND_PACKAGE( PythonInterp ) | 32 | FIND_PACKAGE( PythonInterp ) |
| 25 | FIND_PACKAGE( PythonLibs ) | 33 | FIND_PACKAGE( PythonLibs ) |
| 26 | ENDIF(ENABLE_PYTHON) | 34 | ENDIF(ENABLE_SWIG OR ENABLE_CYTHON) |
| 27 | 35 | ||
| 28 | INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR}/include | 36 | INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR}/include |
| 29 | ${CMAKE_INCLUDE_PATH}) | 37 | ${CMAKE_INCLUDE_PATH}) |
| @@ -52,6 +60,9 @@ ADD_SUBDIRECTORY( test ) | |||
| 52 | IF ( SWIG_FOUND AND PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND ) | 60 | IF ( SWIG_FOUND AND PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND ) |
| 53 | ADD_SUBDIRECTORY( swig ) | 61 | ADD_SUBDIRECTORY( swig ) |
| 54 | ENDIF ( SWIG_FOUND AND PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND ) | 62 | ENDIF ( SWIG_FOUND AND PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND ) |
| 63 | IF ( CYTHON_FOUND AND PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND ) | ||
| 64 | ADD_SUBDIRECTORY( cython ) | ||
| 65 | ENDIF ( CYTHON_FOUND AND PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND ) | ||
| 55 | 66 | ||
| 56 | # add uninstall target | 67 | # add uninstall target |
| 57 | CONFIGURE_FILE( "${CMAKE_SOURCE_DIR}/cmake/modules/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY) | 68 | 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 @@ | |||
| 1 | FIND_PROGRAM(CYTHON_EXECUTABLE cython) | ||
| 2 | |||
| 3 | INCLUDE(FindPackageHandleStandardArgs) | ||
| 4 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(Cython DEFAULT_MSG CYTHON_EXECUTABLE) | ||
| 5 | |||
| 6 | MARK_AS_ADVANCED(CYTHON_EXECUTABLE) | ||
| 7 | |||
| 8 | IF(CYTHON_FOUND) | ||
| 9 | SET(CYTHON_USE_FILE ${CMAKE_SOURCE_DIR}/cmake/modules/UseCython.cmake) | ||
| 10 | 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 @@ | |||
| 1 | |||
| 2 | INCLUDE_DIRECTORIES( ${PYTHON_INCLUDE_PATH} ${CMAKE_CURRENT_SOURCE_DIR} ) | ||
| 3 | |||
| 4 | |||
| 5 | SET(plist_SRC | ||
| 6 | ${CMAKE_CURRENT_BINARY_DIR}/plist.c ) | ||
| 7 | |||
| 8 | SET(plist_HDR | ||
| 9 | ${CMAKE_CURRENT_SOURCE_DIR}/plist.pxd ) | ||
| 10 | |||
| 11 | ADD_CUSTOM_COMMAND( | ||
| 12 | OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/plist.c | ||
| 13 | COMMAND ${CYTHON_EXECUTABLE} -o ${CMAKE_CURRENT_BINARY_DIR}/plist.c ${CMAKE_CURRENT_SOURCE_DIR}/plist.pyx | ||
| 14 | DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/plist.pyx ${CMAKE_CURRENT_SOURCE_DIR}/plist.pxd | ||
| 15 | ) | ||
| 16 | |||
| 17 | |||
| 18 | EXEC_PROGRAM("${PYTHON_EXECUTABLE}" | ||
| 19 | ARGS "-c 'try:\n import distutils.sysconfig; print distutils.sysconfig.get_python_lib(1,0,\"${CMAKE_INSTALL_PREFIX}\")\nexcept: pass\n'" | ||
| 20 | OUTPUT_VARIABLE DISTUTILS_PYTHON_ILIBRARY_PATH | ||
| 21 | ) | ||
| 22 | |||
| 23 | PYTHON_ADD_MODULE(cython_plist plist.c plist_util.c) | ||
| 24 | SET_TARGET_PROPERTIES(cython_plist PROPERTIES PREFIX "" OUTPUT_NAME plist) | ||
| 25 | TARGET_LINK_LIBRARIES(cython_plist plist ${PYTHON_LIBRARIES}) | ||
| 26 | |||
| 27 | INSTALL( FILES ${CMAKE_CURRENT_BINARY_DIR}/plist${CMAKE_SHARED_MODULE_SUFFIX} | ||
| 28 | DESTINATION ${DISTUTILS_PYTHON_ILIBRARY_PATH} ) | ||
| 29 | INSTALL( FILES ${CMAKE_CURRENT_SOURCE_DIR}/plist.pxd | ||
| 30 | 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 @@ | |||
| 1 | cdef extern from "plist/plist.h": | ||
| 2 | ctypedef void *plist_t | ||
| 3 | ctypedef void *plist_dict_iter | ||
| 4 | |||
| 5 | cdef class Node: | ||
| 6 | cdef plist_t _c_node | ||
| 7 | cdef bool _c_managed | ||
| 8 | cpdef object __deepcopy__(self, memo=*) | ||
| 9 | cpdef bytes to_xml(self) | ||
| 10 | cpdef bytes to_bin(self) | ||
| 11 | cpdef object copy(self) | ||
| 12 | |||
| 13 | cdef class Bool(Node): | ||
| 14 | cpdef set_value(self, value) | ||
| 15 | cpdef bool get_value(self) | ||
| 16 | |||
| 17 | cdef class Integer(Node): | ||
| 18 | cpdef set_value(self, value) | ||
| 19 | cpdef int get_value(self) | ||
| 20 | |||
| 21 | cdef class Real(Node): | ||
| 22 | cpdef set_value(self, value) | ||
| 23 | cpdef float get_value(self) | ||
| 24 | |||
| 25 | cdef class String(Node): | ||
| 26 | cpdef set_value(self, unicode value) | ||
| 27 | cpdef unicode get_value(self) | ||
| 28 | |||
| 29 | cdef class Date(Node): | ||
| 30 | cpdef set_value(self, value) | ||
| 31 | cpdef object get_value(self) | ||
| 32 | |||
| 33 | cdef class Data(Node): | ||
| 34 | cpdef set_value(self, bytes value) | ||
| 35 | cpdef bytes get_value(self) | ||
| 36 | |||
| 37 | cdef class Dict(Node): | ||
| 38 | cdef dict _map | ||
| 39 | cdef void _init(self) | ||
| 40 | cpdef set_value(self, dict value) | ||
| 41 | cpdef dict get_value(self) | ||
| 42 | cpdef bool has_key(self, key) | ||
| 43 | cpdef object get(self, key, default=*) | ||
| 44 | cpdef list keys(self) | ||
| 45 | cpdef list items(self) | ||
| 46 | cpdef list values(self) | ||
| 47 | cpdef object iterkeys(self) | ||
| 48 | cpdef object iteritems(self) | ||
| 49 | cpdef object itervalues(self) | ||
| 50 | |||
| 51 | cdef class Array(Node): | ||
| 52 | cdef list _array | ||
| 53 | cdef void _init(self) | ||
| 54 | cpdef set_value(self, value) | ||
| 55 | cpdef list get_value(self) | ||
| 56 | cpdef append(self, item) | ||
| 57 | |||
| 58 | cpdef object from_xml(xml) | ||
| 59 | cpdef object from_bin(bytes bin) | ||
| 60 | |||
| 61 | cdef object plist_t_to_node(plist_t c_plist, bool managed=*) | ||
| 62 | 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 @@ | |||
| 1 | cdef extern from *: | ||
| 2 | ctypedef unsigned char uint8_t | ||
| 3 | ctypedef short int int16_t | ||
| 4 | ctypedef unsigned short int uint16_t | ||
| 5 | ctypedef unsigned int uint32_t | ||
| 6 | ctypedef int int32_t | ||
| 7 | IF UNAME_MACHINE == 'x86_64': | ||
| 8 | ctypedef unsigned long int uint64_t | ||
| 9 | ELSE: | ||
| 10 | ctypedef unsigned long long int uint64_t | ||
| 11 | |||
| 12 | cimport python_unicode | ||
| 13 | |||
| 14 | cdef extern from *: | ||
| 15 | ctypedef enum plist_type: | ||
| 16 | PLIST_BOOLEAN, | ||
| 17 | PLIST_UINT, | ||
| 18 | PLIST_REAL, | ||
| 19 | PLIST_STRING, | ||
| 20 | PLIST_ARRAY, | ||
| 21 | PLIST_DICT, | ||
| 22 | PLIST_DATE, | ||
| 23 | PLIST_DATA, | ||
| 24 | PLIST_KEY, | ||
| 25 | PLIST_NONE | ||
| 26 | |||
| 27 | plist_t plist_new_bool(uint8_t val) | ||
| 28 | void plist_get_bool_val(plist_t node, uint8_t *val) | ||
| 29 | void plist_set_bool_val(plist_t node, uint8_t val) | ||
| 30 | |||
| 31 | plist_t plist_new_uint(uint64_t val) | ||
| 32 | void plist_get_uint_val(plist_t node, uint64_t *val) | ||
| 33 | void plist_set_uint_val(plist_t node, uint64_t val) | ||
| 34 | |||
| 35 | plist_t plist_new_real(double val) | ||
| 36 | void plist_get_real_val(plist_t node, double *val) | ||
| 37 | void plist_set_real_val(plist_t node, double val) | ||
| 38 | |||
| 39 | plist_t plist_new_date(int32_t sec, int32_t usec) | ||
| 40 | void plist_get_date_val(plist_t node, int32_t * sec, int32_t * usec) | ||
| 41 | void plist_set_date_val(plist_t node, int32_t sec, int32_t usec) | ||
| 42 | |||
| 43 | plist_t plist_new_string(char *val) | ||
| 44 | void plist_get_string_val(plist_t node, char **val) | ||
| 45 | void plist_set_string_val(plist_t node, char *val) | ||
| 46 | |||
| 47 | plist_t plist_new_data(char *val, uint64_t length) | ||
| 48 | void plist_get_data_val(plist_t node, char **val, uint64_t * length) | ||
| 49 | void plist_set_data_val(plist_t node, char *val, uint64_t length) | ||
| 50 | |||
| 51 | plist_t plist_new_dict() | ||
| 52 | int plist_dict_get_size(plist_t node) | ||
| 53 | plist_t plist_dict_get_item(plist_t node, char* key) | ||
| 54 | void plist_dict_set_item(plist_t node, char* key, plist_t item) | ||
| 55 | void plist_dict_insert_item(plist_t node, char* key, plist_t item) | ||
| 56 | void plist_dict_remove_item(plist_t node, char* key) | ||
| 57 | |||
| 58 | void plist_dict_new_iter(plist_t node, plist_dict_iter *iter) | ||
| 59 | void plist_dict_next_item(plist_t node, plist_dict_iter iter, char **key, plist_t *val) | ||
| 60 | |||
| 61 | plist_t plist_new_array() | ||
| 62 | uint32_t plist_array_get_size(plist_t node) | ||
| 63 | plist_t plist_array_get_item(plist_t node, uint32_t n) | ||
| 64 | uint32_t plist_array_get_item_index(plist_t node) | ||
| 65 | void plist_array_set_item(plist_t node, plist_t item, uint32_t n) | ||
| 66 | void plist_array_append_item(plist_t node, plist_t item) | ||
| 67 | void plist_array_insert_item(plist_t node, plist_t item, uint32_t n) | ||
| 68 | void plist_array_remove_item(plist_t node, uint32_t n) | ||
| 69 | |||
| 70 | void plist_free(plist_t plist) | ||
| 71 | plist_t plist_copy(plist_t plist) | ||
| 72 | void plist_to_xml(plist_t plist, char **plist_xml, uint32_t *length) | ||
| 73 | void plist_to_bin(plist_t plist, char **plist_bin, uint32_t *length) | ||
| 74 | |||
| 75 | plist_t plist_get_parent(plist_t node) | ||
| 76 | plist_type plist_get_node_type(plist_t node) | ||
| 77 | |||
| 78 | void plist_set_type(plist_t node, plist_type type) | ||
| 79 | |||
| 80 | void plist_from_xml(char *plist_xml, uint32_t length, plist_t * plist) | ||
| 81 | void plist_from_bin(char *plist_bin, uint32_t length, plist_t * plist) | ||
| 82 | |||
| 83 | cdef extern from *: | ||
| 84 | void free(void *ptr) | ||
| 85 | |||
| 86 | cdef class Node: | ||
| 87 | def __init__(self, *args, **kwargs): | ||
| 88 | self._c_managed = True | ||
| 89 | |||
| 90 | def __dealloc__(self): | ||
| 91 | if self._c_node is not NULL and self._c_managed: | ||
| 92 | plist_free(self._c_node) | ||
| 93 | |||
| 94 | cpdef object __deepcopy__(self, memo={}): | ||
| 95 | return plist_t_to_node(plist_copy(self._c_node)) | ||
| 96 | |||
| 97 | cpdef object copy(self): | ||
| 98 | cdef plist_t c_node = NULL | ||
| 99 | c_node = plist_copy(self._c_node) | ||
| 100 | return plist_t_to_node(c_node) | ||
| 101 | |||
| 102 | cpdef bytes to_xml(self): | ||
| 103 | cdef char* out = NULL | ||
| 104 | cdef uint32_t length | ||
| 105 | plist_to_xml(self._c_node, &out, &length) | ||
| 106 | |||
| 107 | return out[:length] | ||
| 108 | |||
| 109 | cpdef bytes to_bin(self): | ||
| 110 | cdef char* out = NULL | ||
| 111 | cdef uint32_t length | ||
| 112 | plist_to_bin(self._c_node, &out, &length) | ||
| 113 | |||
| 114 | return out[:length] | ||
| 115 | |||
| 116 | property parent: | ||
| 117 | def __get__(self): | ||
| 118 | cdef plist_t c_parent = NULL | ||
| 119 | cdef Node node | ||
| 120 | |||
| 121 | c_parent = plist_get_parent(self._c_node) | ||
| 122 | if c_parent == NULL: | ||
| 123 | return None | ||
| 124 | |||
| 125 | return plist_t_to_node(c_parent) | ||
| 126 | |||
| 127 | def __str__(self): | ||
| 128 | return str(self.get_value()) | ||
| 129 | |||
| 130 | cdef class Bool(Node): | ||
| 131 | def __cinit__(self, value=None, *args, **kwargs): | ||
| 132 | if value is None: | ||
| 133 | self._c_node = plist_new_bool(0) | ||
| 134 | else: | ||
| 135 | self._c_node = plist_new_bool(bool(value)) | ||
| 136 | |||
| 137 | def __nonzero__(self): | ||
| 138 | return self.get_value() | ||
| 139 | |||
| 140 | def __richcmp__(self, other, op): | ||
| 141 | cdef bool b = self.get_value() | ||
| 142 | if op == 0: | ||
| 143 | return b < other | ||
| 144 | if op == 1: | ||
| 145 | return b <= other | ||
| 146 | if op == 2: | ||
| 147 | return b == other | ||
| 148 | if op == 3: | ||
| 149 | return b != other | ||
| 150 | if op == 4: | ||
| 151 | return b > other | ||
| 152 | if op == 5: | ||
| 153 | return b >= other | ||
| 154 | |||
| 155 | def __repr__(self): | ||
| 156 | b = self.get_value() | ||
| 157 | return '<Bool: %s>' % b | ||
| 158 | |||
| 159 | cpdef set_value(self, value): | ||
| 160 | plist_set_bool_val(self._c_node, bool(value)) | ||
| 161 | |||
| 162 | cpdef bool get_value(self): | ||
| 163 | cdef uint8_t value | ||
| 164 | plist_get_bool_val(self._c_node, &value) | ||
| 165 | return bool(value) | ||
| 166 | |||
| 167 | cdef Bool Bool_factory(plist_t c_node, bool managed=True): | ||
| 168 | cdef Bool instance = Bool.__new__(Bool) | ||
| 169 | instance._c_managed = managed | ||
| 170 | instance._c_node = c_node | ||
| 171 | return instance | ||
| 172 | |||
| 173 | cdef class Integer(Node): | ||
| 174 | def __cinit__(self, value=None, *args, **kwargs): | ||
| 175 | if value is None: | ||
| 176 | self._c_node = plist_new_uint(0) | ||
| 177 | else: | ||
| 178 | self._c_node = plist_new_uint(int(value)) | ||
| 179 | |||
| 180 | def __repr__(self): | ||
| 181 | i = self.get_value() | ||
| 182 | return '<Integer: %s>' % i | ||
| 183 | |||
| 184 | def __int__(self): | ||
| 185 | return self.get_value() | ||
| 186 | |||
| 187 | def __float__(self): | ||
| 188 | return float(self.get_value()) | ||
| 189 | |||
| 190 | def __richcmp__(self, other, op): | ||
| 191 | cdef int i = self.get_value() | ||
| 192 | if op == 0: | ||
| 193 | return i < other | ||
| 194 | if op == 1: | ||
| 195 | return i <= other | ||
| 196 | if op == 2: | ||
| 197 | return i == other | ||
| 198 | if op == 3: | ||
| 199 | return i != other | ||
| 200 | if op == 4: | ||
| 201 | return i > other | ||
| 202 | if op == 5: | ||
| 203 | return i >= other | ||
| 204 | |||
| 205 | cpdef set_value(self, value): | ||
| 206 | plist_set_uint_val(self._c_node, int(value)) | ||
| 207 | |||
| 208 | cpdef int get_value(self): | ||
| 209 | cdef uint64_t value | ||
| 210 | plist_get_uint_val(self._c_node, &value) | ||
| 211 | return value | ||
| 212 | |||
| 213 | cdef Integer Integer_factory(plist_t c_node, bool managed=True): | ||
| 214 | cdef Integer instance = Integer.__new__(Integer) | ||
| 215 | instance._c_managed = managed | ||
| 216 | instance._c_node = c_node | ||
| 217 | return instance | ||
| 218 | |||
| 219 | cdef class Real(Node): | ||
| 220 | def __cinit__(self, value=None, *args, **kwargs): | ||
| 221 | if value is None: | ||
| 222 | self._c_node = plist_new_real(0.0) | ||
| 223 | else: | ||
| 224 | self._c_node = plist_new_real(float(value)) | ||
| 225 | |||
| 226 | def __repr__(self): | ||
| 227 | r = self.get_value() | ||
| 228 | return '<Real: %s>' % r | ||
| 229 | |||
| 230 | def __float__(self): | ||
| 231 | return self.get_value() | ||
| 232 | |||
| 233 | def __int__(self): | ||
| 234 | return int(self.get_value()) | ||
| 235 | |||
| 236 | def __richcmp__(self, other, op): | ||
| 237 | cdef float f = self.get_value() | ||
| 238 | if op == 0: | ||
| 239 | return f < other | ||
| 240 | if op == 1: | ||
| 241 | return f <= other | ||
| 242 | if op == 2: | ||
| 243 | return f == other | ||
| 244 | if op == 3: | ||
| 245 | return f != other | ||
| 246 | if op == 4: | ||
| 247 | return f > other | ||
| 248 | if op == 5: | ||
| 249 | return f >= other | ||
| 250 | |||
| 251 | cpdef set_value(self, value): | ||
| 252 | plist_set_real_val(self._c_node, float(value)) | ||
| 253 | |||
| 254 | cpdef float get_value(self): | ||
| 255 | cdef double value | ||
| 256 | plist_get_real_val(self._c_node, &value) | ||
| 257 | return value | ||
| 258 | |||
| 259 | cdef Real Real_factory(plist_t c_node, bool managed=True): | ||
| 260 | cdef Real instance = Real.__new__(Real) | ||
| 261 | instance._c_managed = managed | ||
| 262 | instance._c_node = c_node | ||
| 263 | return instance | ||
| 264 | |||
| 265 | from python_version cimport PY_MAJOR_VERSION | ||
| 266 | |||
| 267 | cdef class String(Node): | ||
| 268 | def __cinit__(self, value=None, *args, **kwargs): | ||
| 269 | if value is None: | ||
| 270 | self._c_node = plist_new_string("") | ||
| 271 | else: | ||
| 272 | if isinstance(value, unicode): | ||
| 273 | utf8_data = value.encode('utf-8') | ||
| 274 | elif (PY_MAJOR_VERSION < 3) and isinstance(value, str): | ||
| 275 | value.decode('ascii') | ||
| 276 | utf8_data = value | ||
| 277 | else: | ||
| 278 | raise ValueError("requires text input, got %s" % type(value)) | ||
| 279 | self._c_node = plist_new_string(utf8_data) | ||
| 280 | |||
| 281 | def __repr__(self): | ||
| 282 | s = self.get_value() | ||
| 283 | return '<String: %s>' % s | ||
| 284 | |||
| 285 | def __richcmp__(self, other, op): | ||
| 286 | cdef str s = self.get_value() | ||
| 287 | if op == 0: | ||
| 288 | return s < other | ||
| 289 | if op == 1: | ||
| 290 | return s <= other | ||
| 291 | if op == 2: | ||
| 292 | return s == other | ||
| 293 | if op == 3: | ||
| 294 | return s != other | ||
| 295 | if op == 4: | ||
| 296 | return s > other | ||
| 297 | if op == 5: | ||
| 298 | return s >= other | ||
| 299 | |||
| 300 | cpdef set_value(self, unicode value): | ||
| 301 | if value is None: | ||
| 302 | self._c_node = plist_new_string("") | ||
| 303 | else: | ||
| 304 | if isinstance(value, unicode): | ||
| 305 | utf8_data = value.encode('utf-8') | ||
| 306 | elif (PY_MAJOR_VERSION < 3) and isinstance(value, str): | ||
| 307 | value.decode('ascii') | ||
| 308 | utf8_data = value | ||
| 309 | else: | ||
| 310 | raise ValueError("requires text input, got %s" % type(value)) | ||
| 311 | self._c_node = plist_new_string(utf8_data) | ||
| 312 | |||
| 313 | cpdef unicode get_value(self): | ||
| 314 | cdef char* value = NULL | ||
| 315 | plist_get_string_val(self._c_node, &value) | ||
| 316 | return python_unicode.PyUnicode_DecodeUTF8(value, len(value), 'strict') | ||
| 317 | |||
| 318 | cdef String String_factory(plist_t c_node, bool managed=True): | ||
| 319 | cdef String instance = String.__new__(String) | ||
| 320 | instance._c_managed = managed | ||
| 321 | instance._c_node = c_node | ||
| 322 | return instance | ||
| 323 | |||
| 324 | cdef extern from "plist_util.h": | ||
| 325 | void datetime_to_ints(object obj, int32_t* sec, int32_t* usec) | ||
| 326 | object ints_to_datetime(int32_t sec, int32_t usec) | ||
| 327 | int check_datetime(object obj) | ||
| 328 | |||
| 329 | cdef plist_t create_date_plist(value=None): | ||
| 330 | cdef plist_t node = NULL | ||
| 331 | cdef int32_t secs | ||
| 332 | cdef int32_t usecs | ||
| 333 | if value is None: | ||
| 334 | node = plist_new_date(0, 0) | ||
| 335 | elif check_datetime(value): | ||
| 336 | datetime_to_ints(value, &secs, &usecs) | ||
| 337 | node = plist_new_date(secs, usecs) | ||
| 338 | return node | ||
| 339 | |||
| 340 | cdef class Date(Node): | ||
| 341 | def __cinit__(self, value=None, *args, **kwargs): | ||
| 342 | self._c_node = create_date_plist(value) | ||
| 343 | |||
| 344 | def __repr__(self): | ||
| 345 | d = self.get_value() | ||
| 346 | return '<Date: %s>' % d.ctime() | ||
| 347 | |||
| 348 | def __richcmp__(self, other, op): | ||
| 349 | d = self.get_value() | ||
| 350 | if op == 0: | ||
| 351 | return d < other | ||
| 352 | if op == 1: | ||
| 353 | return d <= other | ||
| 354 | if op == 2: | ||
| 355 | return d == other | ||
| 356 | if op == 3: | ||
| 357 | return d != other | ||
| 358 | if op == 4: | ||
| 359 | return d > other | ||
| 360 | if op == 5: | ||
| 361 | return d >= other | ||
| 362 | |||
| 363 | cpdef object get_value(self): | ||
| 364 | cdef int32_t secs = 0 | ||
| 365 | cdef int32_t usecs = 0 | ||
| 366 | cdef object result | ||
| 367 | plist_get_date_val(self._c_node, &secs, &usecs) | ||
| 368 | return ints_to_datetime(secs, usecs) | ||
| 369 | |||
| 370 | cpdef set_value(self, value): | ||
| 371 | cdef int32_t secs | ||
| 372 | cdef int32_t usecs | ||
| 373 | if not check_datetime(value): | ||
| 374 | raise ValueError("Expected a datetime") | ||
| 375 | datetime_to_ints(value, &secs, &usecs) | ||
| 376 | plist_set_date_val(self._c_node, secs, usecs) | ||
| 377 | |||
| 378 | cdef Date Date_factory(plist_t c_node, bool managed=True): | ||
| 379 | cdef Date instance = Date.__new__(Date) | ||
| 380 | instance._c_managed = managed | ||
| 381 | instance._c_node = c_node | ||
| 382 | return instance | ||
| 383 | |||
| 384 | cdef class Data(Node): | ||
| 385 | def __cinit__(self, value=None, *args, **kwargs): | ||
| 386 | if value is None: | ||
| 387 | self._c_node = plist_new_data(NULL, 0) | ||
| 388 | else: | ||
| 389 | self._c_node = plist_new_data(value, len(value)) | ||
| 390 | |||
| 391 | def __repr__(self): | ||
| 392 | d = self.get_value() | ||
| 393 | return '<Data: %s>' % d | ||
| 394 | |||
| 395 | def __richcmp__(self, other, op): | ||
| 396 | cdef str d = self.get_value() | ||
| 397 | if op == 0: | ||
| 398 | return d < other | ||
| 399 | if op == 1: | ||
| 400 | return d <= other | ||
| 401 | if op == 2: | ||
| 402 | return d == other | ||
| 403 | if op == 3: | ||
| 404 | return d != other | ||
| 405 | if op == 4: | ||
| 406 | return d > other | ||
| 407 | if op == 5: | ||
| 408 | return d >= other | ||
| 409 | |||
| 410 | cpdef bytes get_value(self): | ||
| 411 | cdef char* val = NULL | ||
| 412 | cdef uint64_t length = 0 | ||
| 413 | plist_get_data_val(self._c_node, &val, &length) | ||
| 414 | |||
| 415 | return val[:length] | ||
| 416 | |||
| 417 | cpdef set_value(self, bytes value): | ||
| 418 | plist_set_data_val(self._c_node, value, len(value)) | ||
| 419 | |||
| 420 | cdef Data Data_factory(plist_t c_node, bool managed=True): | ||
| 421 | cdef Data instance = Data.__new__(Data) | ||
| 422 | instance._c_managed = managed | ||
| 423 | instance._c_node = c_node | ||
| 424 | return instance | ||
| 425 | |||
| 426 | cdef plist_t create_dict_plist(value=None): | ||
| 427 | cdef plist_t node = NULL | ||
| 428 | cdef plist_t c_node = NULL | ||
| 429 | node = plist_new_dict() | ||
| 430 | if value is not None and isinstance(value, dict): | ||
| 431 | for key, item in value.items(): | ||
| 432 | c_node = native_to_plist_t(item) | ||
| 433 | plist_dict_insert_item(node, key, c_node) | ||
| 434 | c_node = NULL | ||
| 435 | return node | ||
| 436 | |||
| 437 | cdef class Dict(Node): | ||
| 438 | def __cinit__(self, value=None, *args, **kwargs): | ||
| 439 | self._c_node = create_dict_plist(value) | ||
| 440 | |||
| 441 | def __init__(self, value=None, *args, **kwargs): | ||
| 442 | self._init() | ||
| 443 | |||
| 444 | cdef void _init(self): | ||
| 445 | cdef plist_dict_iter it = NULL | ||
| 446 | cdef char* key = NULL | ||
| 447 | cdef plist_t subnode = NULL | ||
| 448 | |||
| 449 | self._map = {} | ||
| 450 | |||
| 451 | plist_dict_new_iter(self._c_node, &it); | ||
| 452 | plist_dict_next_item(self._c_node, it, &key, &subnode); | ||
| 453 | |||
| 454 | while subnode is not NULL: | ||
| 455 | self._map[key] = plist_t_to_node(subnode, False) | ||
| 456 | subnode = NULL | ||
| 457 | free(key) | ||
| 458 | key = NULL | ||
| 459 | plist_dict_next_item(self._c_node, it, &key, &subnode); | ||
| 460 | free(it) | ||
| 461 | |||
| 462 | def __dealloc__(self): | ||
| 463 | self._map = None | ||
| 464 | Node.__dealloc__(self) | ||
| 465 | |||
| 466 | def __richcmp__(self, other, op): | ||
| 467 | cdef dict d = self.get_value() | ||
| 468 | if op == 0: | ||
| 469 | return d < other | ||
| 470 | if op == 1: | ||
| 471 | return d <= other | ||
| 472 | if op == 2: | ||
| 473 | return d == other | ||
| 474 | if op == 3: | ||
| 475 | return d != other | ||
| 476 | if op == 4: | ||
| 477 | return d > other | ||
| 478 | if op == 5: | ||
| 479 | return d >= other | ||
| 480 | |||
| 481 | def __len__(self): | ||
| 482 | return len(self._map) | ||
| 483 | |||
| 484 | def __repr__(self): | ||
| 485 | return '<Dict: %s>' % self._map | ||
| 486 | |||
| 487 | cpdef dict get_value(self): | ||
| 488 | return dict([(key, value.get_value()) for key, value in self.items()]) | ||
| 489 | |||
| 490 | cpdef set_value(self, dict value): | ||
| 491 | plist_free(self._c_node) | ||
| 492 | self._map = {} | ||
| 493 | self._c_node = NULL | ||
| 494 | self._c_node = create_dict_plist(value) | ||
| 495 | self._init() | ||
| 496 | |||
| 497 | def __iter__(self): | ||
| 498 | return self._map.__iter__() | ||
| 499 | |||
| 500 | cpdef bool has_key(self, key): | ||
| 501 | return self._map.has_key(key) | ||
| 502 | |||
| 503 | cpdef object get(self, key, default=None): | ||
| 504 | return self._map.get(key, default) | ||
| 505 | |||
| 506 | cpdef list keys(self): | ||
| 507 | return self._map.keys() | ||
| 508 | |||
| 509 | cpdef object iterkeys(self): | ||
| 510 | return self._map.iterkeys() | ||
| 511 | |||
| 512 | cpdef list items(self): | ||
| 513 | return self._map.items() | ||
| 514 | |||
| 515 | cpdef object iteritems(self): | ||
| 516 | return self._map.iteritems() | ||
| 517 | |||
| 518 | cpdef list values(self): | ||
| 519 | return self._map.values() | ||
| 520 | |||
| 521 | cpdef object itervalues(self): | ||
| 522 | return self._map.itervalues() | ||
| 523 | |||
| 524 | def __getitem__(self, key): | ||
| 525 | return self._map[key] | ||
| 526 | |||
| 527 | def __setitem__(self, key, value): | ||
| 528 | cdef Node n | ||
| 529 | if isinstance(value, Node): | ||
| 530 | n = value.copy() | ||
| 531 | else: | ||
| 532 | n = plist_t_to_node(native_to_plist_t(value), False) | ||
| 533 | |||
| 534 | plist_dict_insert_item(self._c_node, key, n._c_node) | ||
| 535 | self._map[key] = n | ||
| 536 | |||
| 537 | def __delitem__(self, key): | ||
| 538 | del self._map[key] | ||
| 539 | plist_dict_remove_item(self._c_node, key) | ||
| 540 | |||
| 541 | cdef Dict Dict_factory(plist_t c_node, bool managed=True): | ||
| 542 | cdef Dict instance = Dict.__new__(Dict) | ||
| 543 | instance._c_managed = managed | ||
| 544 | instance._c_node = c_node | ||
| 545 | instance._init() | ||
| 546 | return instance | ||
| 547 | |||
| 548 | cdef plist_t create_array_plist(value=None): | ||
| 549 | cdef plist_t node = NULL | ||
| 550 | cdef plist_t c_node = NULL | ||
| 551 | node = plist_new_array() | ||
| 552 | if value is not None and (isinstance(value, list) or isinstance(value, tuple)): | ||
| 553 | for item in value: | ||
| 554 | c_node = native_to_plist_t(item) | ||
| 555 | plist_array_append_item(node, c_node) | ||
| 556 | c_node = NULL | ||
| 557 | return node | ||
| 558 | |||
| 559 | cdef class Array(Node): | ||
| 560 | def __cinit__(self, value=None, *args, **kwargs): | ||
| 561 | self._c_node = create_array_plist(value) | ||
| 562 | |||
| 563 | def __init__(self, value=None, *args, **kwargs): | ||
| 564 | self._init() | ||
| 565 | |||
| 566 | cdef void _init(self): | ||
| 567 | cdef uint32_t size = plist_array_get_size(self._c_node) | ||
| 568 | cdef plist_t subnode = NULL | ||
| 569 | |||
| 570 | for i from 0 <= i < size: | ||
| 571 | subnode = plist_array_get_item(self._c_node, i) | ||
| 572 | self._array.append(plist_t_to_node(subnode, False)) | ||
| 573 | |||
| 574 | def __richcmp__(self, other, op): | ||
| 575 | cdef list l = self.get_value() | ||
| 576 | if op == 0: | ||
| 577 | return l < other | ||
| 578 | if op == 1: | ||
| 579 | return l <= other | ||
| 580 | if op == 2: | ||
| 581 | return l == other | ||
| 582 | if op == 3: | ||
| 583 | return l != other | ||
| 584 | if op == 4: | ||
| 585 | return l > other | ||
| 586 | if op == 5: | ||
| 587 | return l >= other | ||
| 588 | |||
| 589 | def __len__(self): | ||
| 590 | return len(self._array) | ||
| 591 | |||
| 592 | def __repr__(self): | ||
| 593 | return '<Array: %s>' % self._array | ||
| 594 | |||
| 595 | cpdef list get_value(self): | ||
| 596 | return [i.get_value() for i in self] | ||
| 597 | |||
| 598 | cpdef set_value(self, value): | ||
| 599 | self._array = [] | ||
| 600 | plist_free(self._c_node) | ||
| 601 | self._c_node = NULL | ||
| 602 | self._c_node = create_array_plist(value) | ||
| 603 | self._init() | ||
| 604 | |||
| 605 | def __iter__(self): | ||
| 606 | return self._array.__iter__() | ||
| 607 | |||
| 608 | def __getitem__(self, index): | ||
| 609 | return self._array[index] | ||
| 610 | |||
| 611 | def __setitem__(self, index, value): | ||
| 612 | cdef Node n | ||
| 613 | if isinstance(value, Node): | ||
| 614 | n = value.copy() | ||
| 615 | else: | ||
| 616 | n = plist_t_to_node(native_to_plist_t(value), False) | ||
| 617 | |||
| 618 | if index < 0: | ||
| 619 | index = len(self) + index | ||
| 620 | |||
| 621 | plist_array_set_item(self._c_node, n._c_node, index) | ||
| 622 | self._array[index] = n | ||
| 623 | |||
| 624 | def __delitem__(self, index): | ||
| 625 | if index < 0: | ||
| 626 | index = len(self) + index | ||
| 627 | del self._array[index] | ||
| 628 | plist_array_remove_item(self._c_node, index) | ||
| 629 | |||
| 630 | cpdef append(self, item): | ||
| 631 | cdef Node n | ||
| 632 | |||
| 633 | if isinstance(item, Node): | ||
| 634 | n = item.copy() | ||
| 635 | else: | ||
| 636 | n = plist_t_to_node(native_to_plist_t(item), False) | ||
| 637 | |||
| 638 | plist_array_append_item(self._c_node, n._c_node) | ||
| 639 | self._array.append(n) | ||
| 640 | |||
| 641 | cdef Array Array_factory(plist_t c_node, bool managed=True): | ||
| 642 | cdef Array instance = Array.__new__(Array) | ||
| 643 | instance._c_managed = managed | ||
| 644 | instance._c_node = c_node | ||
| 645 | instance._init() | ||
| 646 | return instance | ||
| 647 | |||
| 648 | cpdef object from_xml(xml): | ||
| 649 | cdef plist_t c_node = NULL | ||
| 650 | plist_from_xml(xml, len(xml), &c_node) | ||
| 651 | return plist_t_to_node(c_node) | ||
| 652 | |||
| 653 | cpdef object from_bin(bytes bin): | ||
| 654 | cdef plist_t c_node = NULL | ||
| 655 | plist_from_bin(bin, len(bin), &c_node) | ||
| 656 | return plist_t_to_node(c_node) | ||
| 657 | |||
| 658 | cdef plist_t native_to_plist_t(object native): | ||
| 659 | cdef plist_t c_node | ||
| 660 | cdef plist_t child_c_node | ||
| 661 | cdef int32_t secs = 0 | ||
| 662 | cdef int32_t usecs = 0 | ||
| 663 | cdef Node node | ||
| 664 | if isinstance(native, Node): | ||
| 665 | node = native | ||
| 666 | return plist_copy(node._c_node) | ||
| 667 | if isinstance(native, basestring): | ||
| 668 | return plist_new_string(native) | ||
| 669 | if isinstance(native, bool): | ||
| 670 | return plist_new_bool(native) | ||
| 671 | if isinstance(native, int) or isinstance(native, long): | ||
| 672 | return plist_new_uint(native) | ||
| 673 | if isinstance(native, float): | ||
| 674 | return plist_new_real(native) | ||
| 675 | if isinstance(native, dict): | ||
| 676 | return create_dict_plist(native) | ||
| 677 | if isinstance(native, list) or isinstance(native, tuple): | ||
| 678 | return create_array_plist(native) | ||
| 679 | if check_datetime(native): | ||
| 680 | return create_date_plist(native) | ||
| 681 | |||
| 682 | cdef object plist_t_to_node(plist_t c_plist, bool managed=True): | ||
| 683 | cdef plist_type t = plist_get_node_type(c_plist) | ||
| 684 | if t == PLIST_BOOLEAN: | ||
| 685 | return Bool_factory(c_plist, managed) | ||
| 686 | if t == PLIST_UINT: | ||
| 687 | return Integer_factory(c_plist, managed) | ||
| 688 | if t == PLIST_REAL: | ||
| 689 | return Real_factory(c_plist, managed) | ||
| 690 | if t == PLIST_STRING: | ||
| 691 | return String_factory(c_plist, managed) | ||
| 692 | if t == PLIST_ARRAY: | ||
| 693 | return Array_factory(c_plist, managed) | ||
| 694 | if t == PLIST_DICT: | ||
| 695 | return Dict_factory(c_plist, managed) | ||
| 696 | if t == PLIST_DATE: | ||
| 697 | return Date_factory(c_plist, managed) | ||
| 698 | if t == PLIST_DATA: | ||
| 699 | 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 @@ | |||
| 1 | #include "plist_util.h" | ||
| 2 | |||
| 3 | #include <time.h> | ||
| 4 | #include <datetime.h> | ||
| 5 | |||
| 6 | void datetime_to_ints(PyObject* obj, int32_t* sec, int32_t* usec) { | ||
| 7 | PyDateTime_IMPORT; | ||
| 8 | if (!PyDateTime_Check(obj)) { | ||
| 9 | PyErr_SetString(PyExc_ValueError,"Expected a datetime"); | ||
| 10 | sec = NULL; | ||
| 11 | usec = NULL; | ||
| 12 | return; | ||
| 13 | } | ||
| 14 | struct tm t = { | ||
| 15 | PyDateTime_DATE_GET_SECOND(obj), | ||
| 16 | PyDateTime_DATE_GET_MINUTE(obj), | ||
| 17 | PyDateTime_DATE_GET_HOUR(obj), | ||
| 18 | PyDateTime_GET_DAY(obj), | ||
| 19 | PyDateTime_GET_MONTH(obj)-1, | ||
| 20 | PyDateTime_GET_YEAR(obj)-1900, | ||
| 21 | 0,0,0 | ||
| 22 | }; | ||
| 23 | *sec = (int32_t)mktime(&t); | ||
| 24 | *usec = PyDateTime_DATE_GET_MICROSECOND(obj); | ||
| 25 | } | ||
| 26 | PyObject* ints_to_datetime(int32_t sec, int32_t usec) { | ||
| 27 | time_t sec_tt = sec; | ||
| 28 | struct tm* t = gmtime(&sec_tt); | ||
| 29 | if(t){ | ||
| 30 | PyDateTime_IMPORT; | ||
| 31 | return PyDateTime_FromDateAndTime(t->tm_year+1900, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, usec); | ||
| 32 | } | ||
| 33 | return NULL; | ||
| 34 | } | ||
| 35 | int check_datetime(PyObject* ob) { | ||
| 36 | if(ob){ | ||
| 37 | PyDateTime_IMPORT; | ||
| 38 | return PyDateTime_Check(ob); | ||
| 39 | } | ||
| 40 | return 0; | ||
| 41 | } | ||
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 @@ | |||
| 1 | #include <Python.h> | ||
| 2 | |||
| 3 | void datetime_to_ints(PyObject* obj, int32_t* sec, int32_t* usec); | ||
| 4 | PyObject* ints_to_datetime(int32_t sec, int32_t usec); | ||
| 5 | int check_datetime(PyObject* obj); | ||
