1/* 2 */ 3#include "pyobjc.h" 4 5static Ivar 6find_ivar(NSObject* base, char* name) 7{ 8 Class cur = object_getClass((id)base); 9 Ivar ivar; 10 11 while (cur != nil) { 12 ivar = class_getInstanceVariable(cur, name); 13 if (ivar != nil) { 14 return ivar; 15 } 16 cur = class_getSuperclass(cur); 17 } 18 return nil; 19} 20 21PyObject* 22PyObjCIvar_Info(PyObject* self __attribute__((__unused__)), PyObject* object) 23{ 24 Class cur; 25 PyObject* v; 26 PyObject* result; 27 int r; 28 29 if (PyObjCObject_Check(object)) { 30 cur = object_getClass((id)PyObjCObject_GetObject(object)); 31 } else if (PyObjCClass_Check(object)) { 32 cur = PyObjCClass_GetClass(object); 33 } else { 34 PyErr_Format(PyExc_TypeError, "not a class or object"); 35 return NULL; 36 } 37 38 39 result = PyList_New(0); 40 if (result == NULL) { 41 return result; 42 } 43 44 /* Handle 'isa' specially, due to Objective-C 2.0 weirdness */ 45 v = Py_BuildValue("(ss)", "isa", @encode(Class)); 46 if (v == NULL) { 47 Py_DECREF(result); 48 return result; 49 } 50 51 r = PyList_Append(result, v); 52 Py_DECREF(v); 53 if (r == -1) { 54 Py_DECREF(result); 55 return result; 56 } 57 58 59 60 while (cur != nil) { 61 Ivar ivar; 62 Ivar* ivarList; 63 unsigned i, ivarCount; 64 65 ivarList = class_copyIvarList(cur, &ivarCount); 66 if (ivarList == NULL) { 67 PyErr_SetString(PyExc_SystemError, "copyIvarList failed"); 68 Py_DECREF(result); 69 return NULL; 70 } 71 72 for (i = 0; i < ivarCount; i++) { 73 ivar = ivarList[i]; 74 const char* ivar_name = ivar_getName(ivar); 75 76 if (ivar == NULL) continue; 77 78 if (strcmp(ivar_name, "isa") == 0) { 79 /* See comment above */ 80 continue; 81 } 82 83 v = Py_BuildValue("(ss)", 84 ivar_name, 85 ivar_getTypeEncoding(ivar)); 86 if (v == NULL) { 87 free(ivarList); 88 Py_DECREF(result); 89 return NULL; 90 } 91 r = PyList_Append(result, v); 92 Py_DECREF(v); 93 if (r == -1) { 94 free(ivarList); 95 Py_DECREF(result); 96 return NULL; 97 } 98 } 99 100 free(ivarList); 101 102 cur = class_getSuperclass(cur); 103 } 104 return result; 105} 106 107PyObject* 108PyObjCIvar_Get(PyObject* self __attribute__((__unused__)), 109 PyObject* args, PyObject* kwds) 110{ 111static char* keywords[] = {"obj", "name", NULL }; 112 PyObject* anObject; 113 char* name; 114 Ivar ivar; 115 NSObject* objcValue; 116 PyObject* result; 117 const char* ivar_type; 118 ptrdiff_t ivar_offset; 119 120 if (!PyArg_ParseTupleAndKeywords(args, kwds, "Os", keywords, &anObject, &name)) { 121 return NULL; 122 } 123 124 if (!PyObjCObject_Check(anObject)) { 125 PyErr_Format(PyExc_TypeError, 126 "Expecting an Objective-C object, got instance of %s", 127 anObject->ob_type->tp_name); 128 return NULL; 129 } 130 131 132 objcValue = PyObjCObject_GetObject(anObject); 133 134 /* Shortcut for isa, mostly due to Objective-C 2.0 weirdness */ 135 if (strcmp(name, "isa") == 0) { 136 Class cls = object_getClass(objcValue); 137 return pythonify_c_value(@encode(Class), &cls); 138 } 139 140 ivar = find_ivar(objcValue, name); 141 if (ivar == NULL) { 142 PyErr_Format(PyExc_AttributeError, "%s", name); 143 return NULL; 144 } 145 146 ivar_type = ivar_getTypeEncoding(ivar); 147 ivar_offset = ivar_getOffset(ivar); 148 149 if (strcmp(ivar_type, @encode(PyObject*)) == 0) { 150 result = *(PyObject**)(((char*)(objcValue)) + ivar_offset); 151 Py_XINCREF(result); 152 } else { 153 result = pythonify_c_value(ivar_type, 154 ((char*)(objcValue)) + ivar_offset); 155 } 156 157 return result; 158} 159 160PyObject* 161PyObjCIvar_Set(PyObject* self __attribute__((__unused__)), 162 PyObject* args, PyObject* kwds) 163{ 164static char* keywords[] = {"obj", "name", "value", "updateRefCounts", NULL }; 165 PyObject* anObject; 166 char* name; 167 Ivar ivar; 168 PyObject* value; 169 PyObject* updateRefCounts = NULL; 170 NSObject* objcValue; 171 int result; 172 const char* ivar_type; 173 ptrdiff_t ivar_offset; 174 175 if (!PyArg_ParseTupleAndKeywords(args, kwds, "OsO|O", 176 keywords, &anObject, &name, &value, &updateRefCounts)) { 177 return NULL; 178 } 179 180 if (!PyObjCObject_Check(anObject)) { 181 PyErr_Format(PyExc_TypeError, 182 "Expecting an Objective-C object, got instance of %s", 183 anObject->ob_type->tp_name); 184 return NULL; 185 } 186 187 objcValue = PyObjCObject_GetObject(anObject); 188 189 if (strcmp(name, "isa") == 0) { 190 /* 191 * Change the class of the object, this means we'll have to 192 * update the python proxy object as well. 193 */ 194 Class cls; 195 PyObject* pycls; 196 197 result = depythonify_c_value(@encode(Class), value, &cls); 198 if (result == -1) { 199 return NULL; 200 } 201 202 (void)object_setClass(objcValue, cls); 203 204 pycls = PyObjCClass_New(cls); 205 if (pycls == NULL) { 206 return NULL; 207 } 208 209 Py_DECREF((PyObject*)(anObject->ob_type)); 210 anObject->ob_type = (PyTypeObject*)pycls; 211 Py_INCREF(Py_None); 212 return Py_None; 213 } 214 215 216 ivar = find_ivar(objcValue, name); 217 if (ivar == NULL) { 218 PyErr_Format(PyExc_AttributeError, "%s", name); 219 return NULL; 220 } 221 222 ivar_type = ivar_getTypeEncoding(ivar); 223 ivar_offset = ivar_getOffset(ivar); 224 225 226 if (strcmp(ivar_type, @encode(PyObject*)) == 0) { 227 /* 228 * Python object, need to handle refcounts 229 */ 230 Py_XINCREF(value); 231 Py_XDECREF(*(PyObject**)(((char*)(objcValue)) + ivar_offset)); 232 *(PyObject**)(((char*)(objcValue)) + ivar_offset) = value; 233 234 } else if (ivar_type[0] == _C_ID) { 235 /* 236 * Objective-C object, need to handle refcounts. 237 */ 238 239 NSObject* tmpValue; 240 241 if (updateRefCounts == NULL) { 242 PyErr_SetString(PyExc_TypeError, 243 "Instance variable is an object, " 244 "updateRefCounts argument is required"); 245 return NULL; 246 } 247 248 result = depythonify_c_value(ivar_type, value, &tmpValue); 249 if (result != 0) { 250 return NULL; 251 } 252 253 if (PyObject_IsTrue(updateRefCounts)) { 254 [tmpValue retain]; 255 256 id v = object_getIvar(objcValue, ivar); 257 [v release]; 258 } 259 object_setIvar(objcValue, ivar, tmpValue); 260 261 } else { 262 /* A simple value */ 263 264 result = depythonify_c_value(ivar_type, value, 265 ((char*)(objcValue)) + ivar_offset); 266 if (result != 0) { 267 return NULL; 268 } 269 } 270 Py_INCREF(Py_None); 271 return Py_None; 272} 273