/Mac/Modules/cf/pycfbridge.c

http://unladen-swallow.googlecode.com/ · C · 303 lines · 263 code · 28 blank · 12 comment · 78 complexity · 46a8cd4e91920186b684548c50c9917e MD5 · raw file

  1. /*
  2. ** Convert objects from Python to CoreFoundation and vice-versa.
  3. */
  4. #include <CoreServices/CoreServices.h>
  5. #include "Python.h"
  6. #include "pymactoolbox.h"
  7. #include "pycfbridge.h"
  8. /* ---------------------------------------- */
  9. /* CoreFoundation objects to Python objects */
  10. /* ---------------------------------------- */
  11. PyObject *
  12. PyCF_CF2Python(CFTypeRef src) {
  13. CFTypeID typeid;
  14. if( src == NULL ) {
  15. Py_INCREF(Py_None);
  16. return Py_None;
  17. }
  18. typeid = CFGetTypeID(src);
  19. if (typeid == CFArrayGetTypeID())
  20. return PyCF_CF2Python_sequence((CFArrayRef)src);
  21. if (typeid == CFDictionaryGetTypeID())
  22. return PyCF_CF2Python_mapping((CFDictionaryRef)src);
  23. return PyCF_CF2Python_simple(src);
  24. }
  25. PyObject *
  26. PyCF_CF2Python_sequence(CFArrayRef src) {
  27. int size = CFArrayGetCount(src);
  28. PyObject *rv;
  29. CFTypeRef item_cf;
  30. PyObject *item_py = NULL;
  31. int i;
  32. if ( (rv=PyList_New(size)) == NULL )
  33. return NULL;
  34. for(i=0; i<size; i++) {
  35. item_cf = CFArrayGetValueAtIndex(src, i);
  36. if (item_cf == NULL ) goto err;
  37. item_py = PyCF_CF2Python(item_cf);
  38. if (item_py == NULL ) goto err;
  39. if (PyList_SetItem(rv, i, item_py) < 0) goto err;
  40. item_py = NULL;
  41. }
  42. return rv;
  43. err:
  44. Py_XDECREF(item_py);
  45. Py_DECREF(rv);
  46. return NULL;
  47. }
  48. PyObject *
  49. PyCF_CF2Python_mapping(CFTypeRef src) {
  50. int size = CFDictionaryGetCount(src);
  51. PyObject *rv = NULL;
  52. CFTypeRef *allkeys = NULL, *allvalues = NULL;
  53. CFTypeRef key_cf, value_cf;
  54. PyObject *key_py = NULL, *value_py = NULL;
  55. int i;
  56. allkeys = malloc(size*sizeof(CFTypeRef *));
  57. if (allkeys == NULL) {
  58. PyErr_NoMemory();
  59. goto err;
  60. }
  61. allvalues = malloc(size*sizeof(CFTypeRef *));
  62. if (allvalues == NULL) {
  63. PyErr_NoMemory();
  64. goto err;
  65. }
  66. if ( (rv=PyDict_New()) == NULL ) goto err;
  67. CFDictionaryGetKeysAndValues(src, allkeys, allvalues);
  68. for(i=0; i<size; i++) {
  69. key_cf = allkeys[i];
  70. value_cf = allvalues[i];
  71. key_py = PyCF_CF2Python(key_cf);
  72. if (key_py == NULL ) goto err;
  73. value_py = PyCF_CF2Python(value_cf);
  74. if (value_py == NULL ) goto err;
  75. if (PyDict_SetItem(rv, key_py, value_py) < 0) goto err;
  76. key_py = NULL;
  77. value_py = NULL;
  78. }
  79. return rv;
  80. err:
  81. Py_XDECREF(key_py);
  82. Py_XDECREF(value_py);
  83. Py_XDECREF(rv);
  84. free(allkeys);
  85. free(allvalues);
  86. return NULL;
  87. }
  88. PyObject *
  89. PyCF_CF2Python_simple(CFTypeRef src) {
  90. CFTypeID typeid;
  91. typeid = CFGetTypeID(src);
  92. if (typeid == CFStringGetTypeID())
  93. return PyCF_CF2Python_string((CFStringRef)src);
  94. if (typeid == CFBooleanGetTypeID())
  95. return PyBool_FromLong((long)CFBooleanGetValue(src));
  96. if (typeid == CFNumberGetTypeID()) {
  97. if (CFNumberIsFloatType(src)) {
  98. double d;
  99. CFNumberGetValue(src, kCFNumberDoubleType, &d);
  100. return PyFloat_FromDouble(d);
  101. } else {
  102. long l;
  103. if (!CFNumberGetValue(src, kCFNumberLongType, &l))
  104. /* XXXX Out of range! */;
  105. return PyInt_FromLong(l);
  106. }
  107. }
  108. /* XXXX Should return as CFTypeRef, really... */
  109. PyMac_Error(resNotFound);
  110. return NULL;
  111. }
  112. /* Unsure - Return unicode or 8 bit strings? */
  113. PyObject *
  114. PyCF_CF2Python_string(CFStringRef src) {
  115. int size = CFStringGetLength(src)+1;
  116. Py_UNICODE *data = malloc(size*sizeof(Py_UNICODE));
  117. CFRange range;
  118. PyObject *rv;
  119. range.location = 0;
  120. range.length = size;
  121. if( data == NULL ) return PyErr_NoMemory();
  122. CFStringGetCharacters(src, range, data);
  123. rv = (PyObject *)PyUnicode_FromUnicode(data, size-1);
  124. free(data);
  125. return rv;
  126. }
  127. /* ---------------------------------------- */
  128. /* Python objects to CoreFoundation objects */
  129. /* ---------------------------------------- */
  130. int
  131. PyCF_Python2CF(PyObject *src, CFTypeRef *dst) {
  132. if (PyString_Check(src) || PyUnicode_Check(src))
  133. return PyCF_Python2CF_simple(src, dst);
  134. if (PySequence_Check(src))
  135. return PyCF_Python2CF_sequence(src, (CFArrayRef *)dst);
  136. if (PyMapping_Check(src))
  137. return PyCF_Python2CF_mapping(src, (CFDictionaryRef *)dst);
  138. return PyCF_Python2CF_simple(src, dst);
  139. }
  140. int
  141. PyCF_Python2CF_sequence(PyObject *src, CFArrayRef *dst) {
  142. CFMutableArrayRef rv = NULL;
  143. CFTypeRef item_cf = NULL;
  144. PyObject *item_py = NULL;
  145. int size, i;
  146. if( !PySequence_Check(src) ) {
  147. PyErr_Format(PyExc_TypeError,
  148. "Cannot convert %.500s objects to CFArray",
  149. src->ob_type->tp_name);
  150. return 0;
  151. }
  152. size = PySequence_Size(src);
  153. rv = CFArrayCreateMutable((CFAllocatorRef)NULL, size, &kCFTypeArrayCallBacks);
  154. if (rv == NULL) {
  155. PyMac_Error(resNotFound);
  156. goto err;
  157. }
  158. for( i=0; i<size; i++) {
  159. item_py = PySequence_GetItem(src, i);
  160. if (item_py == NULL) goto err;
  161. if ( !PyCF_Python2CF(item_py, &item_cf)) goto err;
  162. Py_DECREF(item_py);
  163. CFArraySetValueAtIndex(rv, i, item_cf);
  164. CFRelease(item_cf);
  165. item_cf = NULL;
  166. }
  167. *dst = rv;
  168. return 1;
  169. err:
  170. Py_XDECREF(item_py);
  171. if (rv) CFRelease(rv);
  172. if (item_cf) CFRelease(item_cf);
  173. return 0;
  174. }
  175. int
  176. PyCF_Python2CF_mapping(PyObject *src, CFDictionaryRef *dst) {
  177. CFMutableDictionaryRef rv = NULL;
  178. PyObject *aslist = NULL;
  179. CFTypeRef key_cf = NULL, value_cf = NULL;
  180. PyObject *item_py = NULL, *key_py = NULL, *value_py = NULL;
  181. int size, i;
  182. if( !PyMapping_Check(src) ) {
  183. PyErr_Format(PyExc_TypeError,
  184. "Cannot convert %.500s objects to CFDictionary",
  185. src->ob_type->tp_name);
  186. return 0;
  187. }
  188. size = PyMapping_Size(src);
  189. rv = CFDictionaryCreateMutable((CFAllocatorRef)NULL, size,
  190. &kCFTypeDictionaryKeyCallBacks,
  191. &kCFTypeDictionaryValueCallBacks);
  192. if (rv == NULL) {
  193. PyMac_Error(resNotFound);
  194. goto err;
  195. }
  196. if ( (aslist = PyMapping_Items(src)) == NULL ) goto err;
  197. for( i=0; i<size; i++) {
  198. item_py = PySequence_GetItem(aslist, i);
  199. if (item_py == NULL) goto err;
  200. if (!PyArg_ParseTuple(item_py, "OO", &key_py, &value_py)) goto err;
  201. if ( !PyCF_Python2CF(key_py, &key_cf) ) goto err;
  202. if ( !PyCF_Python2CF(value_py, &value_cf) ) goto err;
  203. CFDictionaryAddValue(rv, key_cf, value_cf);
  204. CFRelease(key_cf);
  205. key_cf = NULL;
  206. CFRelease(value_cf);
  207. value_cf = NULL;
  208. }
  209. *dst = rv;
  210. return 1;
  211. err:
  212. Py_XDECREF(item_py);
  213. Py_XDECREF(aslist);
  214. if (rv) CFRelease(rv);
  215. if (key_cf) CFRelease(key_cf);
  216. if (value_cf) CFRelease(value_cf);
  217. return 0;
  218. }
  219. int
  220. PyCF_Python2CF_simple(PyObject *src, CFTypeRef *dst) {
  221. #if 0
  222. if (PyObject_HasAttrString(src, "CFType")) {
  223. *dst = PyObject_CallMethod(src, "CFType", "");
  224. return (*dst != NULL);
  225. }
  226. #endif
  227. if (PyString_Check(src) || PyUnicode_Check(src))
  228. return PyCF_Python2CF_string(src, (CFStringRef *)dst);
  229. if (PyBool_Check(src)) {
  230. if (src == Py_True)
  231. *dst = kCFBooleanTrue;
  232. else
  233. *dst = kCFBooleanFalse;
  234. return 1;
  235. }
  236. if (PyInt_Check(src)) {
  237. long v = PyInt_AsLong(src);
  238. *dst = CFNumberCreate(NULL, kCFNumberLongType, &v);
  239. return 1;
  240. }
  241. if (PyFloat_Check(src)) {
  242. double d = PyFloat_AsDouble(src);
  243. *dst = CFNumberCreate(NULL, kCFNumberDoubleType, &d);
  244. return 1;
  245. }
  246. PyErr_Format(PyExc_TypeError,
  247. "Cannot convert %.500s objects to CFType",
  248. src->ob_type->tp_name);
  249. return 0;
  250. }
  251. int
  252. PyCF_Python2CF_string(PyObject *src, CFStringRef *dst) {
  253. char *chars;
  254. CFIndex size;
  255. UniChar *unichars;
  256. if (PyString_Check(src)) {
  257. if (!PyArg_Parse(src, "es", "ascii", &chars))
  258. return 0; /* This error is more descriptive than the general one below */
  259. *dst = CFStringCreateWithCString((CFAllocatorRef)NULL, chars, kCFStringEncodingASCII);
  260. PyMem_Free(chars);
  261. return 1;
  262. }
  263. if (PyUnicode_Check(src)) {
  264. /* We use the CF types here, if Python was configured differently that will give an error */
  265. size = PyUnicode_GetSize(src);
  266. if ((unichars = PyUnicode_AsUnicode(src)) == NULL ) goto err;
  267. *dst = CFStringCreateWithCharacters((CFAllocatorRef)NULL, unichars, size);
  268. return 1;
  269. }
  270. err:
  271. PyErr_Format(PyExc_TypeError,
  272. "Cannot convert %.500s objects to CFString",
  273. src->ob_type->tp_name);
  274. return 0;
  275. }