blob: 1b7d7c5950f292872fc97aab1aabde91c6fe6b54 [file] [log] [blame]
Jack Jansenefaffae2002-05-05 21:48:12 +00001/*
2** Convert objects from Python to CoreFoundation and vice-versa.
3*/
4
5#ifdef WITHOUT_FRAMEWORKS
6#include <CFBase.h>
Jack Jansen42251322002-05-08 22:13:51 +00007#include <CFNumber.h>
Jack Jansenefaffae2002-05-05 21:48:12 +00008#include <CFArray.h>
9#include <CFData.h>
10#include <CFDictionary.h>
11#include <CFString.h>
12#include <CFURL.h>
13#else
14#include <CoreServices/CoreServices.h>
15#endif
16
17#include "Python.h"
18#include "macglue.h"
19#include "pycfbridge.h"
20
21
22/* ---------------------------------------- */
23/* CoreFoundation objects to Python objects */
24/* ---------------------------------------- */
25
26PyObject *
27PyCF_CF2Python(CFTypeRef src) {
28 CFTypeID typeid;
29
Jack Jansen5ad6f7a2002-05-07 23:00:03 +000030 if( src == NULL ) {
31 Py_INCREF(Py_None);
32 return Py_None;
33 }
Jack Jansenefaffae2002-05-05 21:48:12 +000034 typeid = CFGetTypeID(src);
35 if (typeid == CFArrayGetTypeID())
36 return PyCF_CF2Python_sequence((CFArrayRef)src);
37 if (typeid == CFDictionaryGetTypeID())
38 return PyCF_CF2Python_mapping((CFDictionaryRef)src);
39 return PyCF_CF2Python_simple(src);
40}
41
42PyObject *
43PyCF_CF2Python_sequence(CFArrayRef src) {
Jack Jansen5ad6f7a2002-05-07 23:00:03 +000044 int size = CFArrayGetCount(src);
45 PyObject *rv;
46 CFTypeRef item_cf;
47 PyObject *item_py = NULL;
48 int i;
49
50 if ( (rv=PyList_New(size)) == NULL )
51 return NULL;
52 for(i=0; i<size; i++) {
53 item_cf = CFArrayGetValueAtIndex(src, i);
54 if (item_cf == NULL ) goto err;
55 item_py = PyCF_CF2Python(item_cf);
56 if (item_py == NULL ) goto err;
Jack Jansen1df628d2002-05-08 15:29:33 +000057 if (PyList_SetItem(rv, i, item_py) < 0) goto err;
Jack Jansen5ad6f7a2002-05-07 23:00:03 +000058 item_py = NULL;
59 }
60 return rv;
61err:
62 Py_XDECREF(item_py);
63 Py_DECREF(rv);
Jack Jansenefaffae2002-05-05 21:48:12 +000064 return NULL;
65}
66
67PyObject *
68PyCF_CF2Python_mapping(CFTypeRef src) {
Jack Jansen5ad6f7a2002-05-07 23:00:03 +000069 int size = CFDictionaryGetCount(src);
Jack Jansen42251322002-05-08 22:13:51 +000070 PyObject *rv = NULL;
71 CFTypeRef *allkeys = NULL, *allvalues = NULL;
Jack Jansen5ad6f7a2002-05-07 23:00:03 +000072 CFTypeRef key_cf, value_cf;
73 PyObject *key_py = NULL, *value_py = NULL;
74 int i;
75
76 allkeys = malloc(size*sizeof(CFTypeRef *));
Jack Jansen42251322002-05-08 22:13:51 +000077 if (allkeys == NULL) {
78 PyErr_NoMemory();
79 goto err;
80 }
Jack Jansen5ad6f7a2002-05-07 23:00:03 +000081 allvalues = malloc(size*sizeof(CFTypeRef *));
Jack Jansen42251322002-05-08 22:13:51 +000082 if (allvalues == NULL) {
83 PyErr_NoMemory();
84 goto err;
85 }
86 if ( (rv=PyDict_New()) == NULL ) goto err;
Jack Jansen5ad6f7a2002-05-07 23:00:03 +000087 CFDictionaryGetKeysAndValues(src, allkeys, allvalues);
88 for(i=0; i<size; i++) {
89 key_cf = allkeys[i];
90 value_cf = allvalues[i];
91 key_py = PyCF_CF2Python(key_cf);
92 if (key_py == NULL ) goto err;
Jack Jansen42251322002-05-08 22:13:51 +000093 value_py = PyCF_CF2Python(value_cf);
Jack Jansen5ad6f7a2002-05-07 23:00:03 +000094 if (value_py == NULL ) goto err;
Jack Jansen1df628d2002-05-08 15:29:33 +000095 if (PyDict_SetItem(rv, key_py, value_py) < 0) goto err;
Jack Jansen5ad6f7a2002-05-07 23:00:03 +000096 key_py = NULL;
97 value_py = NULL;
98 }
99 return rv;
100err:
101 Py_XDECREF(key_py);
102 Py_XDECREF(value_py);
Jack Jansen42251322002-05-08 22:13:51 +0000103 Py_XDECREF(rv);
Jack Jansen5ad6f7a2002-05-07 23:00:03 +0000104 free(allkeys);
105 free(allvalues);
Jack Jansenefaffae2002-05-05 21:48:12 +0000106 return NULL;
107}
108
109PyObject *
110PyCF_CF2Python_simple(CFTypeRef src) {
111 CFTypeID typeid;
112
113 typeid = CFGetTypeID(src);
114 if (typeid == CFStringGetTypeID())
115 return PyCF_CF2Python_string((CFStringRef)src);
Jack Jansen42251322002-05-08 22:13:51 +0000116 if (typeid == CFBooleanGetTypeID())
117 return PyBool_FromLong((long)CFBooleanGetValue(src));
118 if (typeid == CFNumberGetTypeID()) {
119 if (CFNumberIsFloatType(src)) {
120 double d;
121 CFNumberGetValue(src, kCFNumberDoubleType, &d);
122 return PyFloat_FromDouble(d);
123 } else {
124 long l;
125 if (!CFNumberGetValue(src, kCFNumberLongType, &l))
126 /* XXXX Out of range! */;
127 return PyInt_FromLong(l);
128 }
129 }
130 /* XXXX Should return as CFTypeRef, really... */
Jack Jansenefaffae2002-05-05 21:48:12 +0000131 PyMac_Error(resNotFound);
132 return NULL;
133}
134
135/* Unsure - Return unicode or 8 bit strings? */
136PyObject *
137PyCF_CF2Python_string(CFStringRef src) {
138 int size = CFStringGetLength(src)+1;
139 Py_UNICODE *data = malloc(size*sizeof(Py_UNICODE));
140 CFRange range;
141 PyObject *rv;
142
143 range.location = 0;
144 range.length = size;
145 if( data == NULL ) return PyErr_NoMemory();
146 CFStringGetCharacters(src, range, data);
Jack Jansen42251322002-05-08 22:13:51 +0000147 rv = (PyObject *)PyUnicode_FromUnicode(data, size-1);
Jack Jansenefaffae2002-05-05 21:48:12 +0000148 free(data);
149 return rv;
150}
151
152/* ---------------------------------------- */
153/* Python objects to CoreFoundation objects */
154/* ---------------------------------------- */
155
156int
157PyCF_Python2CF(PyObject *src, CFTypeRef *dst) {
158
Jack Jansen1df628d2002-05-08 15:29:33 +0000159 if (PyString_Check(src) || PyUnicode_Check(src))
160 return PyCF_Python2CF_simple(src, dst);
Jack Jansenefaffae2002-05-05 21:48:12 +0000161 if (PySequence_Check(src))
162 return PyCF_Python2CF_sequence(src, (CFArrayRef *)dst);
163 if (PyMapping_Check(src))
164 return PyCF_Python2CF_mapping(src, (CFDictionaryRef *)dst);
165 return PyCF_Python2CF_simple(src, dst);
166}
167
168int
169PyCF_Python2CF_sequence(PyObject *src, CFArrayRef *dst) {
Jack Jansen5ad6f7a2002-05-07 23:00:03 +0000170 CFMutableArrayRef rv = NULL;
Jack Jansenefaffae2002-05-05 21:48:12 +0000171 CFTypeRef item_cf = NULL;
172 PyObject *item_py = NULL;
173 int size, i;
174
175 size = PySequence_Size(src);
176 rv = CFArrayCreateMutable((CFAllocatorRef)NULL, size, &kCFTypeArrayCallBacks);
177 if (rv == NULL) {
178 PyMac_Error(resNotFound);
179 goto err;
180 }
181
182 for( i=0; i<size; i++) {
183 item_py = PySequence_GetItem(src, i);
184 if (item_py == NULL) goto err;
185 if ( !PyCF_Python2CF(item_py, &item_cf)) goto err;
186 Py_DECREF(item_py);
187 CFArraySetValueAtIndex(rv, i, item_cf);
188 CFRelease(item_cf);
189 item_cf = NULL;
190 }
191 *dst = rv;
192 return 1;
193err:
194 Py_XDECREF(item_py);
195 if (rv) CFRelease(rv);
196 if (item_cf) CFRelease(item_cf);
197 return 0;
198}
199
200int
201PyCF_Python2CF_mapping(PyObject *src, CFDictionaryRef *dst) {
Jack Jansen5ad6f7a2002-05-07 23:00:03 +0000202 CFMutableDictionaryRef rv = NULL;
Jack Jansenefaffae2002-05-05 21:48:12 +0000203 PyObject *aslist = NULL;
204 CFTypeRef key_cf = NULL, value_cf = NULL;
205 PyObject *item_py = NULL, *key_py = NULL, *value_py = NULL;
206 int size, i;
207
208 size = PyMapping_Size(src);
209 rv = CFDictionaryCreateMutable((CFAllocatorRef)NULL, size,
Jack Jansen5ad6f7a2002-05-07 23:00:03 +0000210 &kCFTypeDictionaryKeyCallBacks,
Jack Jansenefaffae2002-05-05 21:48:12 +0000211 &kCFTypeDictionaryValueCallBacks);
212 if (rv == NULL) {
213 PyMac_Error(resNotFound);
214 goto err;
215 }
216 if ( (aslist = PyMapping_Items(src)) == NULL ) goto err;
217
218 for( i=0; i<size; i++) {
219 item_py = PySequence_GetItem(aslist, i);
220 if (item_py == NULL) goto err;
Jack Jansen42251322002-05-08 22:13:51 +0000221 if (!PyArg_ParseTuple(item_py, "OO", &key_py, &value_py)) goto err;
Jack Jansenefaffae2002-05-05 21:48:12 +0000222 if ( !PyCF_Python2CF(key_py, &key_cf) ) goto err;
Jack Jansen5ad6f7a2002-05-07 23:00:03 +0000223 if ( !PyCF_Python2CF(value_py, &value_cf) ) goto err;
Jack Jansenefaffae2002-05-05 21:48:12 +0000224 CFDictionaryAddValue(rv, key_cf, value_cf);
225 CFRelease(key_cf);
226 key_cf = NULL;
227 CFRelease(value_cf);
228 value_cf = NULL;
229 }
230 *dst = rv;
231 return 1;
232err:
233 Py_XDECREF(item_py);
Jack Jansenefaffae2002-05-05 21:48:12 +0000234 Py_XDECREF(aslist);
235 if (rv) CFRelease(rv);
236 if (key_cf) CFRelease(key_cf);
237 if (value_cf) CFRelease(value_cf);
238 return 0;
239}
240
241int
242PyCF_Python2CF_simple(PyObject *src, CFTypeRef *dst) {
243
244 if (PyObject_HasAttrString(src, "CFType")) {
245 *dst = PyObject_CallMethod(src, "CFType", "");
246 return (*dst != NULL);
247 }
248 if (PyString_Check(src) || PyUnicode_Check(src))
249 return PyCF_Python2CF_string(src, (CFStringRef *)dst);
Jack Jansen42251322002-05-08 22:13:51 +0000250 if (PyBool_Check(src)) {
251 if (src == Py_True)
252 *dst = kCFBooleanTrue;
253 else
254 *dst = kCFBooleanFalse;
255 return 1;
256 }
257 if (PyInt_Check(src)) {
258 long v = PyInt_AsLong(src);
259 *dst = CFNumberCreate(NULL, kCFNumberLongType, &v);
260 return 1;
261 }
262 if (PyFloat_Check(src)) {
263 double d = PyFloat_AsDouble(src);
264 *dst = CFNumberCreate(NULL, kCFNumberDoubleType, &d);
265 return 1;
266 }
267
Jack Jansenefaffae2002-05-05 21:48:12 +0000268 PyErr_Format(PyExc_TypeError,
269 "Cannot convert %.500s objects to CF",
270 src->ob_type->tp_name);
271 return 0;
272}
273
274int
275PyCF_Python2CF_string(PyObject *src, CFStringRef *dst) {
276 char *chars;
277 CFIndex size;
278 UniChar *unichars;
279
280 if (PyString_Check(src)) {
281 if ((chars = PyString_AsString(src)) == NULL ) goto err;
282 *dst = CFStringCreateWithCString((CFAllocatorRef)NULL, chars, 0);
283 return 1;
284 }
285 if (PyUnicode_Check(src)) {
286 /* We use the CF types here, if Python was configured differently that will give an error */
287 size = PyUnicode_GetSize(src);
288 if ((unichars = PyUnicode_AsUnicode(src)) == NULL ) goto err;
289 *dst = CFStringCreateWithCharacters((CFAllocatorRef)NULL, unichars, size);
290 return 1;
291 }
292err:
293 PyErr_Format(PyExc_TypeError,
294 "Cannot convert %.500s objects to CF",
295 src->ob_type->tp_name);
296 return 0;
297}