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 * 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 * 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 * 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 * 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 * 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 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 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 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 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 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