blob: eb476ed43dc3469711438c90e49667dced0e5d04 [file] [log] [blame]
Jack Jansenefaffae2002-05-05 21:48:12 +00001/*
2** Convert objects from Python to CoreFoundation and vice-versa.
3*/
4
Jack Jansenefaffae2002-05-05 21:48:12 +00005#include <CoreServices/CoreServices.h>
Jack Jansenefaffae2002-05-05 21:48:12 +00006
7#include "Python.h"
Jack Jansen7107c1a2003-11-20 13:31:00 +00008#include "pymactoolbox.h"
Jack Jansenefaffae2002-05-05 21:48:12 +00009#include "pycfbridge.h"
10
11
12/* ---------------------------------------- */
13/* CoreFoundation objects to Python objects */
14/* ---------------------------------------- */
15
16PyObject *
17PyCF_CF2Python(CFTypeRef src) {
18 CFTypeID typeid;
19
Jack Jansen5ad6f7a2002-05-07 23:00:03 +000020 if( src == NULL ) {
21 Py_INCREF(Py_None);
22 return Py_None;
23 }
Jack Jansenefaffae2002-05-05 21:48:12 +000024 typeid = CFGetTypeID(src);
25 if (typeid == CFArrayGetTypeID())
26 return PyCF_CF2Python_sequence((CFArrayRef)src);
27 if (typeid == CFDictionaryGetTypeID())
28 return PyCF_CF2Python_mapping((CFDictionaryRef)src);
29 return PyCF_CF2Python_simple(src);
30}
31
32PyObject *
33PyCF_CF2Python_sequence(CFArrayRef src) {
Jack Jansen5ad6f7a2002-05-07 23:00:03 +000034 int size = CFArrayGetCount(src);
35 PyObject *rv;
36 CFTypeRef item_cf;
37 PyObject *item_py = NULL;
38 int i;
39
40 if ( (rv=PyList_New(size)) == NULL )
41 return NULL;
42 for(i=0; i<size; i++) {
43 item_cf = CFArrayGetValueAtIndex(src, i);
44 if (item_cf == NULL ) goto err;
45 item_py = PyCF_CF2Python(item_cf);
46 if (item_py == NULL ) goto err;
Jack Jansen1df628d2002-05-08 15:29:33 +000047 if (PyList_SetItem(rv, i, item_py) < 0) goto err;
Jack Jansen5ad6f7a2002-05-07 23:00:03 +000048 item_py = NULL;
49 }
50 return rv;
51err:
52 Py_XDECREF(item_py);
53 Py_DECREF(rv);
Jack Jansenefaffae2002-05-05 21:48:12 +000054 return NULL;
55}
56
57PyObject *
58PyCF_CF2Python_mapping(CFTypeRef src) {
Jack Jansen5ad6f7a2002-05-07 23:00:03 +000059 int size = CFDictionaryGetCount(src);
Jack Jansen42251322002-05-08 22:13:51 +000060 PyObject *rv = NULL;
61 CFTypeRef *allkeys = NULL, *allvalues = NULL;
Jack Jansen5ad6f7a2002-05-07 23:00:03 +000062 CFTypeRef key_cf, value_cf;
63 PyObject *key_py = NULL, *value_py = NULL;
64 int i;
65
66 allkeys = malloc(size*sizeof(CFTypeRef *));
Jack Jansen42251322002-05-08 22:13:51 +000067 if (allkeys == NULL) {
68 PyErr_NoMemory();
69 goto err;
70 }
Jack Jansen5ad6f7a2002-05-07 23:00:03 +000071 allvalues = malloc(size*sizeof(CFTypeRef *));
Jack Jansen42251322002-05-08 22:13:51 +000072 if (allvalues == NULL) {
73 PyErr_NoMemory();
74 goto err;
75 }
76 if ( (rv=PyDict_New()) == NULL ) goto err;
Jack Jansen5ad6f7a2002-05-07 23:00:03 +000077 CFDictionaryGetKeysAndValues(src, allkeys, allvalues);
78 for(i=0; i<size; i++) {
79 key_cf = allkeys[i];
80 value_cf = allvalues[i];
81 key_py = PyCF_CF2Python(key_cf);
82 if (key_py == NULL ) goto err;
Jack Jansen42251322002-05-08 22:13:51 +000083 value_py = PyCF_CF2Python(value_cf);
Jack Jansen5ad6f7a2002-05-07 23:00:03 +000084 if (value_py == NULL ) goto err;
Jack Jansen1df628d2002-05-08 15:29:33 +000085 if (PyDict_SetItem(rv, key_py, value_py) < 0) goto err;
Jack Jansen5ad6f7a2002-05-07 23:00:03 +000086 key_py = NULL;
87 value_py = NULL;
88 }
89 return rv;
90err:
91 Py_XDECREF(key_py);
92 Py_XDECREF(value_py);
Jack Jansen42251322002-05-08 22:13:51 +000093 Py_XDECREF(rv);
Jack Jansen5ad6f7a2002-05-07 23:00:03 +000094 free(allkeys);
95 free(allvalues);
Jack Jansenefaffae2002-05-05 21:48:12 +000096 return NULL;
97}
98
99PyObject *
100PyCF_CF2Python_simple(CFTypeRef src) {
101 CFTypeID typeid;
102
103 typeid = CFGetTypeID(src);
104 if (typeid == CFStringGetTypeID())
105 return PyCF_CF2Python_string((CFStringRef)src);
Jack Jansen42251322002-05-08 22:13:51 +0000106 if (typeid == CFBooleanGetTypeID())
107 return PyBool_FromLong((long)CFBooleanGetValue(src));
108 if (typeid == CFNumberGetTypeID()) {
109 if (CFNumberIsFloatType(src)) {
110 double d;
111 CFNumberGetValue(src, kCFNumberDoubleType, &d);
112 return PyFloat_FromDouble(d);
113 } else {
114 long l;
115 if (!CFNumberGetValue(src, kCFNumberLongType, &l))
116 /* XXXX Out of range! */;
Christian Heimes217cfd12007-12-02 14:31:20 +0000117 return PyLong_FromLong(l);
Jack Jansen42251322002-05-08 22:13:51 +0000118 }
119 }
120 /* XXXX Should return as CFTypeRef, really... */
Jack Jansenefaffae2002-05-05 21:48:12 +0000121 PyMac_Error(resNotFound);
122 return NULL;
123}
124
125/* Unsure - Return unicode or 8 bit strings? */
126PyObject *
127PyCF_CF2Python_string(CFStringRef src) {
128 int size = CFStringGetLength(src)+1;
129 Py_UNICODE *data = malloc(size*sizeof(Py_UNICODE));
130 CFRange range;
131 PyObject *rv;
132
133 range.location = 0;
134 range.length = size;
135 if( data == NULL ) return PyErr_NoMemory();
136 CFStringGetCharacters(src, range, data);
Jack Jansen42251322002-05-08 22:13:51 +0000137 rv = (PyObject *)PyUnicode_FromUnicode(data, size-1);
Jack Jansenefaffae2002-05-05 21:48:12 +0000138 free(data);
139 return rv;
140}
141
142/* ---------------------------------------- */
143/* Python objects to CoreFoundation objects */
144/* ---------------------------------------- */
145
146int
147PyCF_Python2CF(PyObject *src, CFTypeRef *dst) {
148
Jack Jansen1df628d2002-05-08 15:29:33 +0000149 if (PyString_Check(src) || PyUnicode_Check(src))
150 return PyCF_Python2CF_simple(src, dst);
Jack Jansenefaffae2002-05-05 21:48:12 +0000151 if (PySequence_Check(src))
152 return PyCF_Python2CF_sequence(src, (CFArrayRef *)dst);
153 if (PyMapping_Check(src))
154 return PyCF_Python2CF_mapping(src, (CFDictionaryRef *)dst);
155 return PyCF_Python2CF_simple(src, dst);
156}
157
158int
159PyCF_Python2CF_sequence(PyObject *src, CFArrayRef *dst) {
Jack Jansen5ad6f7a2002-05-07 23:00:03 +0000160 CFMutableArrayRef rv = NULL;
Jack Jansenefaffae2002-05-05 21:48:12 +0000161 CFTypeRef item_cf = NULL;
162 PyObject *item_py = NULL;
163 int size, i;
164
Jack Janseneaba9d72002-05-13 21:23:10 +0000165 if( !PySequence_Check(src) ) {
166 PyErr_Format(PyExc_TypeError,
167 "Cannot convert %.500s objects to CFArray",
168 src->ob_type->tp_name);
169 return 0;
170 }
Jack Jansenefaffae2002-05-05 21:48:12 +0000171 size = PySequence_Size(src);
172 rv = CFArrayCreateMutable((CFAllocatorRef)NULL, size, &kCFTypeArrayCallBacks);
173 if (rv == NULL) {
174 PyMac_Error(resNotFound);
175 goto err;
176 }
177
178 for( i=0; i<size; i++) {
179 item_py = PySequence_GetItem(src, i);
180 if (item_py == NULL) goto err;
181 if ( !PyCF_Python2CF(item_py, &item_cf)) goto err;
182 Py_DECREF(item_py);
183 CFArraySetValueAtIndex(rv, i, item_cf);
184 CFRelease(item_cf);
185 item_cf = NULL;
186 }
187 *dst = rv;
188 return 1;
189err:
190 Py_XDECREF(item_py);
191 if (rv) CFRelease(rv);
192 if (item_cf) CFRelease(item_cf);
193 return 0;
194}
195
196int
197PyCF_Python2CF_mapping(PyObject *src, CFDictionaryRef *dst) {
Jack Jansen5ad6f7a2002-05-07 23:00:03 +0000198 CFMutableDictionaryRef rv = NULL;
Jack Jansenefaffae2002-05-05 21:48:12 +0000199 PyObject *aslist = NULL;
200 CFTypeRef key_cf = NULL, value_cf = NULL;
201 PyObject *item_py = NULL, *key_py = NULL, *value_py = NULL;
202 int size, i;
203
Jack Janseneaba9d72002-05-13 21:23:10 +0000204 if( !PyMapping_Check(src) ) {
205 PyErr_Format(PyExc_TypeError,
206 "Cannot convert %.500s objects to CFDictionary",
207 src->ob_type->tp_name);
208 return 0;
209 }
Jack Jansenefaffae2002-05-05 21:48:12 +0000210 size = PyMapping_Size(src);
211 rv = CFDictionaryCreateMutable((CFAllocatorRef)NULL, size,
Jack Jansen5ad6f7a2002-05-07 23:00:03 +0000212 &kCFTypeDictionaryKeyCallBacks,
Jack Jansenefaffae2002-05-05 21:48:12 +0000213 &kCFTypeDictionaryValueCallBacks);
214 if (rv == NULL) {
215 PyMac_Error(resNotFound);
216 goto err;
217 }
218 if ( (aslist = PyMapping_Items(src)) == NULL ) goto err;
219
220 for( i=0; i<size; i++) {
221 item_py = PySequence_GetItem(aslist, i);
222 if (item_py == NULL) goto err;
Jack Jansen42251322002-05-08 22:13:51 +0000223 if (!PyArg_ParseTuple(item_py, "OO", &key_py, &value_py)) goto err;
Jack Jansenefaffae2002-05-05 21:48:12 +0000224 if ( !PyCF_Python2CF(key_py, &key_cf) ) goto err;
Jack Jansen5ad6f7a2002-05-07 23:00:03 +0000225 if ( !PyCF_Python2CF(value_py, &value_cf) ) goto err;
Jack Jansenefaffae2002-05-05 21:48:12 +0000226 CFDictionaryAddValue(rv, key_cf, value_cf);
227 CFRelease(key_cf);
228 key_cf = NULL;
229 CFRelease(value_cf);
230 value_cf = NULL;
231 }
232 *dst = rv;
233 return 1;
234err:
235 Py_XDECREF(item_py);
Jack Jansenefaffae2002-05-05 21:48:12 +0000236 Py_XDECREF(aslist);
237 if (rv) CFRelease(rv);
238 if (key_cf) CFRelease(key_cf);
239 if (value_cf) CFRelease(value_cf);
240 return 0;
241}
242
243int
244PyCF_Python2CF_simple(PyObject *src, CFTypeRef *dst) {
245
Jack Janseneaba9d72002-05-13 21:23:10 +0000246#if 0
Jack Jansenefaffae2002-05-05 21:48:12 +0000247 if (PyObject_HasAttrString(src, "CFType")) {
248 *dst = PyObject_CallMethod(src, "CFType", "");
249 return (*dst != NULL);
250 }
Jack Janseneaba9d72002-05-13 21:23:10 +0000251#endif
Jack Jansenefaffae2002-05-05 21:48:12 +0000252 if (PyString_Check(src) || PyUnicode_Check(src))
253 return PyCF_Python2CF_string(src, (CFStringRef *)dst);
Jack Jansen42251322002-05-08 22:13:51 +0000254 if (PyBool_Check(src)) {
255 if (src == Py_True)
256 *dst = kCFBooleanTrue;
257 else
258 *dst = kCFBooleanFalse;
259 return 1;
260 }
Christian Heimes217cfd12007-12-02 14:31:20 +0000261 if (PyLong_Check(src)) {
262 long v = PyLong_AsLong(src);
Jack Jansen42251322002-05-08 22:13:51 +0000263 *dst = CFNumberCreate(NULL, kCFNumberLongType, &v);
264 return 1;
265 }
266 if (PyFloat_Check(src)) {
267 double d = PyFloat_AsDouble(src);
268 *dst = CFNumberCreate(NULL, kCFNumberDoubleType, &d);
269 return 1;
270 }
271
Jack Jansenefaffae2002-05-05 21:48:12 +0000272 PyErr_Format(PyExc_TypeError,
Jack Janseneaba9d72002-05-13 21:23:10 +0000273 "Cannot convert %.500s objects to CFType",
Jack Jansenefaffae2002-05-05 21:48:12 +0000274 src->ob_type->tp_name);
275 return 0;
276}
277
278int
279PyCF_Python2CF_string(PyObject *src, CFStringRef *dst) {
280 char *chars;
281 CFIndex size;
282 UniChar *unichars;
283
284 if (PyString_Check(src)) {
Jack Jansen885d4f62003-03-03 13:19:44 +0000285 if (!PyArg_Parse(src, "es", "ascii", &chars))
Neal Norwitz8786eb52006-02-24 15:39:29 +0000286 return 0; /* This error is more descriptive than the general one below */
Jack Jansend505cab2003-03-03 13:12:59 +0000287 *dst = CFStringCreateWithCString((CFAllocatorRef)NULL, chars, kCFStringEncodingASCII);
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000288 PyMem_Free(chars);
Jack Jansenefaffae2002-05-05 21:48:12 +0000289 return 1;
290 }
291 if (PyUnicode_Check(src)) {
292 /* We use the CF types here, if Python was configured differently that will give an error */
293 size = PyUnicode_GetSize(src);
294 if ((unichars = PyUnicode_AsUnicode(src)) == NULL ) goto err;
295 *dst = CFStringCreateWithCharacters((CFAllocatorRef)NULL, unichars, size);
296 return 1;
297 }
298err:
299 PyErr_Format(PyExc_TypeError,
Jack Janseneaba9d72002-05-13 21:23:10 +0000300 "Cannot convert %.500s objects to CFString",
Jack Jansenefaffae2002-05-05 21:48:12 +0000301 src->ob_type->tp_name);
302 return 0;
303}