append(): Fixing the test for convertability after consultation with
[python/dscho.git] / Mac / Modules / cf / pycfbridge.c
blob00efa725196519add0eb9e26b7b7d00331d19f65
1 /*
2 ** Convert objects from Python to CoreFoundation and vice-versa.
3 */
5 #ifdef WITHOUT_FRAMEWORKS
6 #include <CFBase.h>
7 #include <CFNumber.h>
8 #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
17 #include "Python.h"
18 #include "macglue.h"
19 #include "pycfbridge.h"
22 /* ---------------------------------------- */
23 /* CoreFoundation objects to Python objects */
24 /* ---------------------------------------- */
26 PyObject *
27 PyCF_CF2Python(CFTypeRef src) {
28 CFTypeID typeid;
30 if( src == NULL ) {
31 Py_INCREF(Py_None);
32 return Py_None;
34 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);
42 PyObject *
43 PyCF_CF2Python_sequence(CFArrayRef src) {
44 int size = CFArrayGetCount(src);
45 PyObject *rv;
46 CFTypeRef item_cf;
47 PyObject *item_py = NULL;
48 int i;
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;
57 if (PyList_SetItem(rv, i, item_py) < 0) goto err;
58 item_py = NULL;
60 return rv;
61 err:
62 Py_XDECREF(item_py);
63 Py_DECREF(rv);
64 return NULL;
67 PyObject *
68 PyCF_CF2Python_mapping(CFTypeRef src) {
69 int size = CFDictionaryGetCount(src);
70 PyObject *rv = NULL;
71 CFTypeRef *allkeys = NULL, *allvalues = NULL;
72 CFTypeRef key_cf, value_cf;
73 PyObject *key_py = NULL, *value_py = NULL;
74 int i;
76 allkeys = malloc(size*sizeof(CFTypeRef *));
77 if (allkeys == NULL) {
78 PyErr_NoMemory();
79 goto err;
81 allvalues = malloc(size*sizeof(CFTypeRef *));
82 if (allvalues == NULL) {
83 PyErr_NoMemory();
84 goto err;
86 if ( (rv=PyDict_New()) == NULL ) goto err;
87 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;
93 value_py = PyCF_CF2Python(value_cf);
94 if (value_py == NULL ) goto err;
95 if (PyDict_SetItem(rv, key_py, value_py) < 0) goto err;
96 key_py = NULL;
97 value_py = NULL;
99 return rv;
100 err:
101 Py_XDECREF(key_py);
102 Py_XDECREF(value_py);
103 Py_XDECREF(rv);
104 free(allkeys);
105 free(allvalues);
106 return NULL;
109 PyObject *
110 PyCF_CF2Python_simple(CFTypeRef src) {
111 CFTypeID typeid;
113 typeid = CFGetTypeID(src);
114 if (typeid == CFStringGetTypeID())
115 return PyCF_CF2Python_string((CFStringRef)src);
116 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);
130 /* XXXX Should return as CFTypeRef, really... */
131 PyMac_Error(resNotFound);
132 return NULL;
135 /* Unsure - Return unicode or 8 bit strings? */
136 PyObject *
137 PyCF_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;
143 range.location = 0;
144 range.length = size;
145 if( data == NULL ) return PyErr_NoMemory();
146 CFStringGetCharacters(src, range, data);
147 rv = (PyObject *)PyUnicode_FromUnicode(data, size-1);
148 free(data);
149 return rv;
152 /* ---------------------------------------- */
153 /* Python objects to CoreFoundation objects */
154 /* ---------------------------------------- */
157 PyCF_Python2CF(PyObject *src, CFTypeRef *dst) {
159 if (PyString_Check(src) || PyUnicode_Check(src))
160 return PyCF_Python2CF_simple(src, dst);
161 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);
169 PyCF_Python2CF_sequence(PyObject *src, CFArrayRef *dst) {
170 CFMutableArrayRef rv = NULL;
171 CFTypeRef item_cf = NULL;
172 PyObject *item_py = NULL;
173 int size, i;
175 if( !PySequence_Check(src) ) {
176 PyErr_Format(PyExc_TypeError,
177 "Cannot convert %.500s objects to CFArray",
178 src->ob_type->tp_name);
179 return 0;
181 size = PySequence_Size(src);
182 rv = CFArrayCreateMutable((CFAllocatorRef)NULL, size, &kCFTypeArrayCallBacks);
183 if (rv == NULL) {
184 PyMac_Error(resNotFound);
185 goto err;
188 for( i=0; i<size; i++) {
189 item_py = PySequence_GetItem(src, i);
190 if (item_py == NULL) goto err;
191 if ( !PyCF_Python2CF(item_py, &item_cf)) goto err;
192 Py_DECREF(item_py);
193 CFArraySetValueAtIndex(rv, i, item_cf);
194 CFRelease(item_cf);
195 item_cf = NULL;
197 *dst = rv;
198 return 1;
199 err:
200 Py_XDECREF(item_py);
201 if (rv) CFRelease(rv);
202 if (item_cf) CFRelease(item_cf);
203 return 0;
207 PyCF_Python2CF_mapping(PyObject *src, CFDictionaryRef *dst) {
208 CFMutableDictionaryRef rv = NULL;
209 PyObject *aslist = NULL;
210 CFTypeRef key_cf = NULL, value_cf = NULL;
211 PyObject *item_py = NULL, *key_py = NULL, *value_py = NULL;
212 int size, i;
214 if( !PyMapping_Check(src) ) {
215 PyErr_Format(PyExc_TypeError,
216 "Cannot convert %.500s objects to CFDictionary",
217 src->ob_type->tp_name);
218 return 0;
220 size = PyMapping_Size(src);
221 rv = CFDictionaryCreateMutable((CFAllocatorRef)NULL, size,
222 &kCFTypeDictionaryKeyCallBacks,
223 &kCFTypeDictionaryValueCallBacks);
224 if (rv == NULL) {
225 PyMac_Error(resNotFound);
226 goto err;
228 if ( (aslist = PyMapping_Items(src)) == NULL ) goto err;
230 for( i=0; i<size; i++) {
231 item_py = PySequence_GetItem(aslist, i);
232 if (item_py == NULL) goto err;
233 if (!PyArg_ParseTuple(item_py, "OO", &key_py, &value_py)) goto err;
234 if ( !PyCF_Python2CF(key_py, &key_cf) ) goto err;
235 if ( !PyCF_Python2CF(value_py, &value_cf) ) goto err;
236 CFDictionaryAddValue(rv, key_cf, value_cf);
237 CFRelease(key_cf);
238 key_cf = NULL;
239 CFRelease(value_cf);
240 value_cf = NULL;
242 *dst = rv;
243 return 1;
244 err:
245 Py_XDECREF(item_py);
246 Py_XDECREF(aslist);
247 if (rv) CFRelease(rv);
248 if (key_cf) CFRelease(key_cf);
249 if (value_cf) CFRelease(value_cf);
250 return 0;
254 PyCF_Python2CF_simple(PyObject *src, CFTypeRef *dst) {
256 #if 0
257 if (PyObject_HasAttrString(src, "CFType")) {
258 *dst = PyObject_CallMethod(src, "CFType", "");
259 return (*dst != NULL);
261 #endif
262 if (PyString_Check(src) || PyUnicode_Check(src))
263 return PyCF_Python2CF_string(src, (CFStringRef *)dst);
264 if (PyBool_Check(src)) {
265 if (src == Py_True)
266 *dst = kCFBooleanTrue;
267 else
268 *dst = kCFBooleanFalse;
269 return 1;
271 if (PyInt_Check(src)) {
272 long v = PyInt_AsLong(src);
273 *dst = CFNumberCreate(NULL, kCFNumberLongType, &v);
274 return 1;
276 if (PyFloat_Check(src)) {
277 double d = PyFloat_AsDouble(src);
278 *dst = CFNumberCreate(NULL, kCFNumberDoubleType, &d);
279 return 1;
282 PyErr_Format(PyExc_TypeError,
283 "Cannot convert %.500s objects to CFType",
284 src->ob_type->tp_name);
285 return 0;
289 PyCF_Python2CF_string(PyObject *src, CFStringRef *dst) {
290 char *chars;
291 CFIndex size;
292 UniChar *unichars;
294 if (PyString_Check(src)) {
295 if ((chars = PyString_AsString(src)) == NULL ) goto err;
296 *dst = CFStringCreateWithCString((CFAllocatorRef)NULL, chars, 0);
297 return 1;
299 if (PyUnicode_Check(src)) {
300 /* We use the CF types here, if Python was configured differently that will give an error */
301 size = PyUnicode_GetSize(src);
302 if ((unichars = PyUnicode_AsUnicode(src)) == NULL ) goto err;
303 *dst = CFStringCreateWithCharacters((CFAllocatorRef)NULL, unichars, size);
304 return 1;
306 err:
307 PyErr_Format(PyExc_TypeError,
308 "Cannot convert %.500s objects to CFString",
309 src->ob_type->tp_name);
310 return 0;