• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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