1 /*
2 ** Convert objects from Python to CoreFoundation and vice-versa.
3 */
4
5 #include <CoreServices/CoreServices.h>
6
7 #include "Python.h"
8 #include "pymactoolbox.h"
9 #include "pycfbridge.h"
10
11
12 /* ---------------------------------------- */
13 /* CoreFoundation objects to Python objects */
14 /* ---------------------------------------- */
15
16 PyObject *
PyCF_CF2Python(CFTypeRef src)17 PyCF_CF2Python(CFTypeRef src) {
18 CFTypeID typeid;
19
20 if( src == NULL ) {
21 Py_INCREF(Py_None);
22 return Py_None;
23 }
24 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
32 PyObject *
PyCF_CF2Python_sequence(CFArrayRef src)33 PyCF_CF2Python_sequence(CFArrayRef src) {
34 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;
47 if (PyList_SetItem(rv, i, item_py) < 0) goto err;
48 item_py = NULL;
49 }
50 return rv;
51 err:
52 Py_XDECREF(item_py);
53 Py_DECREF(rv);
54 return NULL;
55 }
56
57 PyObject *
PyCF_CF2Python_mapping(CFTypeRef src)58 PyCF_CF2Python_mapping(CFTypeRef src) {
59 int size = CFDictionaryGetCount(src);
60 PyObject *rv = NULL;
61 CFTypeRef *allkeys = NULL, *allvalues = NULL;
62 CFTypeRef key_cf, value_cf;
63 PyObject *key_py = NULL, *value_py = NULL;
64 int i;
65
66 allkeys = malloc(size*sizeof(CFTypeRef *));
67 if (allkeys == NULL) {
68 PyErr_NoMemory();
69 goto err;
70 }
71 allvalues = malloc(size*sizeof(CFTypeRef *));
72 if (allvalues == NULL) {
73 PyErr_NoMemory();
74 goto err;
75 }
76 if ( (rv=PyDict_New()) == NULL ) goto err;
77 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;
83 value_py = PyCF_CF2Python(value_cf);
84 if (value_py == NULL ) goto err;
85 if (PyDict_SetItem(rv, key_py, value_py) < 0) goto err;
86 key_py = NULL;
87 value_py = NULL;
88 }
89 return rv;
90 err:
91 Py_XDECREF(key_py);
92 Py_XDECREF(value_py);
93 Py_XDECREF(rv);
94 free(allkeys);
95 free(allvalues);
96 return NULL;
97 }
98
99 PyObject *
PyCF_CF2Python_simple(CFTypeRef src)100 PyCF_CF2Python_simple(CFTypeRef src) {
101 CFTypeID typeid;
102
103 typeid = CFGetTypeID(src);
104 if (typeid == CFStringGetTypeID())
105 return PyCF_CF2Python_string((CFStringRef)src);
106 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! */;
117 return PyInt_FromLong(l);
118 }
119 }
120 /* XXXX Should return as CFTypeRef, really... */
121 PyMac_Error(resNotFound);
122 return NULL;
123 }
124
125 /* Unsure - Return unicode or 8 bit strings? */
126 PyObject *
PyCF_CF2Python_string(CFStringRef src)127 PyCF_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);
137 rv = (PyObject *)PyUnicode_FromUnicode(data, size-1);
138 free(data);
139 return rv;
140 }
141
142 /* ---------------------------------------- */
143 /* Python objects to CoreFoundation objects */
144 /* ---------------------------------------- */
145
146 int
PyCF_Python2CF(PyObject * src,CFTypeRef * dst)147 PyCF_Python2CF(PyObject *src, CFTypeRef *dst) {
148
149 if (PyString_Check(src) || PyUnicode_Check(src))
150 return PyCF_Python2CF_simple(src, dst);
151 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
158 int
PyCF_Python2CF_sequence(PyObject * src,CFArrayRef * dst)159 PyCF_Python2CF_sequence(PyObject *src, CFArrayRef *dst) {
160 CFMutableArrayRef rv = NULL;
161 CFTypeRef item_cf = NULL;
162 PyObject *item_py = NULL;
163 int size, i;
164
165 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 }
171 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;
189 err:
190 Py_XDECREF(item_py);
191 if (rv) CFRelease(rv);
192 if (item_cf) CFRelease(item_cf);
193 return 0;
194 }
195
196 int
PyCF_Python2CF_mapping(PyObject * src,CFDictionaryRef * dst)197 PyCF_Python2CF_mapping(PyObject *src, CFDictionaryRef *dst) {
198 CFMutableDictionaryRef rv = NULL;
199 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
204 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 }
210 size = PyMapping_Size(src);
211 rv = CFDictionaryCreateMutable((CFAllocatorRef)NULL, size,
212 &kCFTypeDictionaryKeyCallBacks,
213 &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;
223 if (!PyArg_ParseTuple(item_py, "OO", &key_py, &value_py)) goto err;
224 if ( !PyCF_Python2CF(key_py, &key_cf) ) goto err;
225 if ( !PyCF_Python2CF(value_py, &value_cf) ) goto err;
226 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;
234 err:
235 Py_XDECREF(item_py);
236 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
243 int
PyCF_Python2CF_simple(PyObject * src,CFTypeRef * dst)244 PyCF_Python2CF_simple(PyObject *src, CFTypeRef *dst) {
245
246 #if 0
247 if (PyObject_HasAttrString(src, "CFType")) {
248 *dst = PyObject_CallMethod(src, "CFType", "");
249 return (*dst != NULL);
250 }
251 #endif
252 if (PyString_Check(src) || PyUnicode_Check(src))
253 return PyCF_Python2CF_string(src, (CFStringRef *)dst);
254 if (PyBool_Check(src)) {
255 if (src == Py_True)
256 *dst = kCFBooleanTrue;
257 else
258 *dst = kCFBooleanFalse;
259 return 1;
260 }
261 if (PyInt_Check(src)) {
262 long v = PyInt_AsLong(src);
263 *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
272 PyErr_Format(PyExc_TypeError,
273 "Cannot convert %.500s objects to CFType",
274 src->ob_type->tp_name);
275 return 0;
276 }
277
278 int
PyCF_Python2CF_string(PyObject * src,CFStringRef * dst)279 PyCF_Python2CF_string(PyObject *src, CFStringRef *dst) {
280 char *chars;
281 CFIndex size;
282 UniChar *unichars;
283
284 if (PyString_Check(src)) {
285 if (!PyArg_Parse(src, "es", "ascii", &chars))
286 return 0; /* This error is more descriptive than the general one below */
287 *dst = CFStringCreateWithCString((CFAllocatorRef)NULL, chars, kCFStringEncodingASCII);
288 PyMem_Free(chars);
289 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 }
298 err:
299 PyErr_Format(PyExc_TypeError,
300 "Cannot convert %.500s objects to CFString",
301 src->ob_type->tp_name);
302 return 0;
303 }
304