Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 1 | #include "Python.h" |
| 2 | #include <ffi.h> |
| 3 | #ifdef MS_WIN32 |
| 4 | #include <windows.h> |
Thomas Heller | b041fda | 2008-04-30 17:11:46 +0000 | [diff] [blame] | 5 | #include <malloc.h> |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 6 | #endif |
| 7 | #include "ctypes.h" |
| 8 | |
| 9 | /******************************************************************/ |
| 10 | /* |
| 11 | StdDict - a dictionary subclass, containing additional C accessible fields |
| 12 | |
| 13 | XXX blabla more |
| 14 | */ |
| 15 | |
| 16 | /* Seems we need this, otherwise we get problems when calling |
| 17 | * PyDict_SetItem() (ma_lookup is NULL) |
| 18 | */ |
| 19 | static int |
Thomas Heller | 34596a9 | 2009-04-24 20:50:00 +0000 | [diff] [blame] | 20 | PyCStgDict_init(StgDictObject *self, PyObject *args, PyObject *kwds) |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 21 | { |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 22 | if (PyDict_Type.tp_init((PyObject *)self, args, kwds) < 0) |
| 23 | return -1; |
| 24 | self->format = NULL; |
| 25 | self->ndim = 0; |
| 26 | self->shape = NULL; |
| 27 | return 0; |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 28 | } |
| 29 | |
| 30 | static int |
Thomas Heller | 34596a9 | 2009-04-24 20:50:00 +0000 | [diff] [blame] | 31 | PyCStgDict_clear(StgDictObject *self) |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 32 | { |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 33 | Py_CLEAR(self->proto); |
| 34 | Py_CLEAR(self->argtypes); |
| 35 | Py_CLEAR(self->converters); |
| 36 | Py_CLEAR(self->restype); |
| 37 | Py_CLEAR(self->checker); |
| 38 | return 0; |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 39 | } |
| 40 | |
| 41 | static void |
Thomas Heller | 34596a9 | 2009-04-24 20:50:00 +0000 | [diff] [blame] | 42 | PyCStgDict_dealloc(StgDictObject *self) |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 43 | { |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 44 | PyCStgDict_clear(self); |
| 45 | PyMem_Free(self->format); |
| 46 | PyMem_Free(self->shape); |
| 47 | PyMem_Free(self->ffi_type_pointer.elements); |
| 48 | PyDict_Type.tp_dealloc((PyObject *)self); |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 49 | } |
| 50 | |
| 51 | int |
Thomas Heller | 34596a9 | 2009-04-24 20:50:00 +0000 | [diff] [blame] | 52 | PyCStgDict_clone(StgDictObject *dst, StgDictObject *src) |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 53 | { |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 54 | char *d, *s; |
| 55 | Py_ssize_t size; |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 56 | |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 57 | PyCStgDict_clear(dst); |
| 58 | PyMem_Free(dst->ffi_type_pointer.elements); |
| 59 | PyMem_Free(dst->format); |
| 60 | dst->format = NULL; |
| 61 | PyMem_Free(dst->shape); |
| 62 | dst->shape = NULL; |
| 63 | dst->ffi_type_pointer.elements = NULL; |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 64 | |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 65 | d = (char *)dst; |
| 66 | s = (char *)src; |
| 67 | memcpy(d + sizeof(PyDictObject), |
| 68 | s + sizeof(PyDictObject), |
| 69 | sizeof(StgDictObject) - sizeof(PyDictObject)); |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 70 | |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 71 | Py_XINCREF(dst->proto); |
| 72 | Py_XINCREF(dst->argtypes); |
| 73 | Py_XINCREF(dst->converters); |
| 74 | Py_XINCREF(dst->restype); |
| 75 | Py_XINCREF(dst->checker); |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 76 | |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 77 | if (src->format) { |
| 78 | dst->format = PyMem_Malloc(strlen(src->format) + 1); |
| 79 | if (dst->format == NULL) |
| 80 | return -1; |
| 81 | strcpy(dst->format, src->format); |
| 82 | } |
| 83 | if (src->shape) { |
| 84 | dst->shape = PyMem_Malloc(sizeof(Py_ssize_t) * src->ndim); |
| 85 | if (dst->shape == NULL) |
| 86 | return -1; |
| 87 | memcpy(dst->shape, src->shape, |
| 88 | sizeof(Py_ssize_t) * src->ndim); |
| 89 | } |
Thomas Heller | b041fda | 2008-04-30 17:11:46 +0000 | [diff] [blame] | 90 | |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 91 | if (src->ffi_type_pointer.elements == NULL) |
| 92 | return 0; |
| 93 | size = sizeof(ffi_type *) * (src->length + 1); |
| 94 | dst->ffi_type_pointer.elements = PyMem_Malloc(size); |
| 95 | if (dst->ffi_type_pointer.elements == NULL) { |
| 96 | PyErr_NoMemory(); |
| 97 | return -1; |
| 98 | } |
| 99 | memcpy(dst->ffi_type_pointer.elements, |
| 100 | src->ffi_type_pointer.elements, |
| 101 | size); |
| 102 | return 0; |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 103 | } |
| 104 | |
Thomas Heller | 34596a9 | 2009-04-24 20:50:00 +0000 | [diff] [blame] | 105 | PyTypeObject PyCStgDict_Type = { |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 106 | PyVarObject_HEAD_INIT(NULL, 0) |
| 107 | "StgDict", |
| 108 | sizeof(StgDictObject), |
| 109 | 0, |
| 110 | (destructor)PyCStgDict_dealloc, /* tp_dealloc */ |
| 111 | 0, /* tp_print */ |
| 112 | 0, /* tp_getattr */ |
| 113 | 0, /* tp_setattr */ |
| 114 | 0, /* tp_reserved */ |
| 115 | 0, /* tp_repr */ |
| 116 | 0, /* tp_as_number */ |
| 117 | 0, /* tp_as_sequence */ |
| 118 | 0, /* tp_as_mapping */ |
| 119 | 0, /* tp_hash */ |
| 120 | 0, /* tp_call */ |
| 121 | 0, /* tp_str */ |
| 122 | 0, /* tp_getattro */ |
| 123 | 0, /* tp_setattro */ |
| 124 | 0, /* tp_as_buffer */ |
| 125 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ |
| 126 | 0, /* tp_doc */ |
| 127 | 0, /* tp_traverse */ |
| 128 | 0, /* tp_clear */ |
| 129 | 0, /* tp_richcompare */ |
| 130 | 0, /* tp_weaklistoffset */ |
| 131 | 0, /* tp_iter */ |
| 132 | 0, /* tp_iternext */ |
| 133 | 0, /* tp_methods */ |
| 134 | 0, /* tp_members */ |
| 135 | 0, /* tp_getset */ |
| 136 | 0, /* tp_base */ |
| 137 | 0, /* tp_dict */ |
| 138 | 0, /* tp_descr_get */ |
| 139 | 0, /* tp_descr_set */ |
| 140 | 0, /* tp_dictoffset */ |
| 141 | (initproc)PyCStgDict_init, /* tp_init */ |
| 142 | 0, /* tp_alloc */ |
| 143 | 0, /* tp_new */ |
| 144 | 0, /* tp_free */ |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 145 | }; |
| 146 | |
| 147 | /* May return NULL, but does not set an exception! */ |
| 148 | StgDictObject * |
| 149 | PyType_stgdict(PyObject *obj) |
| 150 | { |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 151 | PyTypeObject *type; |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 152 | |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 153 | if (!PyType_Check(obj)) |
| 154 | return NULL; |
| 155 | type = (PyTypeObject *)obj; |
| 156 | if (!type->tp_dict || !PyCStgDict_CheckExact(type->tp_dict)) |
| 157 | return NULL; |
| 158 | return (StgDictObject *)type->tp_dict; |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 159 | } |
| 160 | |
| 161 | /* May return NULL, but does not set an exception! */ |
Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 162 | /* |
| 163 | This function should be as fast as possible, so we don't call PyType_stgdict |
| 164 | above but inline the code, and avoid the PyType_Check(). |
| 165 | */ |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 166 | StgDictObject * |
| 167 | PyObject_stgdict(PyObject *self) |
| 168 | { |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 169 | PyTypeObject *type = self->ob_type; |
| 170 | if (!type->tp_dict || !PyCStgDict_CheckExact(type->tp_dict)) |
| 171 | return NULL; |
| 172 | return (StgDictObject *)type->tp_dict; |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 173 | } |
| 174 | |
Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 175 | /* descr is the descriptor for a field marked as anonymous. Get all the |
| 176 | _fields_ descriptors from descr->proto, create new descriptors with offset |
| 177 | and index adjusted, and stuff them into type. |
| 178 | */ |
| 179 | static int |
| 180 | MakeFields(PyObject *type, CFieldObject *descr, |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 181 | Py_ssize_t index, Py_ssize_t offset) |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 182 | { |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 183 | Py_ssize_t i; |
| 184 | PyObject *fields; |
| 185 | PyObject *fieldlist; |
Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 186 | |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 187 | fields = PyObject_GetAttrString(descr->proto, "_fields_"); |
| 188 | if (fields == NULL) |
| 189 | return -1; |
| 190 | fieldlist = PySequence_Fast(fields, "_fields_ must be a sequence"); |
| 191 | Py_DECREF(fields); |
| 192 | if (fieldlist == NULL) |
| 193 | return -1; |
Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 194 | |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 195 | for (i = 0; i < PySequence_Fast_GET_SIZE(fieldlist); ++i) { |
| 196 | PyObject *pair = PySequence_Fast_GET_ITEM(fieldlist, i); /* borrowed */ |
| 197 | PyObject *fname, *ftype, *bits; |
| 198 | CFieldObject *fdescr; |
| 199 | CFieldObject *new_descr; |
| 200 | /* Convert to PyArg_UnpackTuple... */ |
| 201 | if (!PyArg_ParseTuple(pair, "OO|O", &fname, &ftype, &bits)) { |
| 202 | Py_DECREF(fieldlist); |
| 203 | return -1; |
| 204 | } |
| 205 | fdescr = (CFieldObject *)PyObject_GetAttr(descr->proto, fname); |
| 206 | if (fdescr == NULL) { |
| 207 | Py_DECREF(fieldlist); |
| 208 | return -1; |
| 209 | } |
| 210 | if (Py_TYPE(fdescr) != &PyCField_Type) { |
| 211 | PyErr_SetString(PyExc_TypeError, "unexpected type"); |
| 212 | Py_DECREF(fdescr); |
| 213 | Py_DECREF(fieldlist); |
| 214 | return -1; |
| 215 | } |
| 216 | if (fdescr->anonymous) { |
| 217 | int rc = MakeFields(type, fdescr, |
| 218 | index + fdescr->index, |
| 219 | offset + fdescr->offset); |
| 220 | Py_DECREF(fdescr); |
| 221 | if (rc == -1) { |
| 222 | Py_DECREF(fieldlist); |
| 223 | return -1; |
| 224 | } |
| 225 | continue; |
| 226 | } |
| 227 | new_descr = (CFieldObject *)PyObject_CallObject((PyObject *)&PyCField_Type, NULL); |
| 228 | if (new_descr == NULL) { |
| 229 | Py_DECREF(fdescr); |
| 230 | Py_DECREF(fieldlist); |
| 231 | return -1; |
| 232 | } |
| 233 | assert(Py_TYPE(new_descr) == &PyCField_Type); |
| 234 | new_descr->size = fdescr->size; |
| 235 | new_descr->offset = fdescr->offset + offset; |
| 236 | new_descr->index = fdescr->index + index; |
| 237 | new_descr->proto = fdescr->proto; |
| 238 | Py_XINCREF(new_descr->proto); |
| 239 | new_descr->getfunc = fdescr->getfunc; |
| 240 | new_descr->setfunc = fdescr->setfunc; |
Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 241 | |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 242 | Py_DECREF(fdescr); |
| 243 | |
| 244 | if (-1 == PyObject_SetAttr(type, fname, (PyObject *)new_descr)) { |
| 245 | Py_DECREF(fieldlist); |
| 246 | Py_DECREF(new_descr); |
| 247 | return -1; |
| 248 | } |
| 249 | Py_DECREF(new_descr); |
| 250 | } |
| 251 | Py_DECREF(fieldlist); |
| 252 | return 0; |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 253 | } |
Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 254 | |
| 255 | /* Iterate over the names in the type's _anonymous_ attribute, if present, |
| 256 | */ |
| 257 | static int |
| 258 | MakeAnonFields(PyObject *type) |
| 259 | { |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 260 | PyObject *anon; |
| 261 | PyObject *anon_names; |
| 262 | Py_ssize_t i; |
Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 263 | |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 264 | anon = PyObject_GetAttrString(type, "_anonymous_"); |
| 265 | if (anon == NULL) { |
| 266 | PyErr_Clear(); |
| 267 | return 0; |
| 268 | } |
| 269 | anon_names = PySequence_Fast(anon, "_anonymous_ must be a sequence"); |
| 270 | Py_DECREF(anon); |
| 271 | if (anon_names == NULL) |
| 272 | return -1; |
Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 273 | |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 274 | for (i = 0; i < PySequence_Fast_GET_SIZE(anon_names); ++i) { |
| 275 | PyObject *fname = PySequence_Fast_GET_ITEM(anon_names, i); /* borrowed */ |
| 276 | CFieldObject *descr = (CFieldObject *)PyObject_GetAttr(type, fname); |
| 277 | if (descr == NULL) { |
| 278 | Py_DECREF(anon_names); |
| 279 | return -1; |
| 280 | } |
| 281 | assert(Py_TYPE(descr) == &PyCField_Type); |
| 282 | descr->anonymous = 1; |
Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 283 | |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 284 | /* descr is in the field descriptor. */ |
| 285 | if (-1 == MakeFields(type, (CFieldObject *)descr, |
| 286 | ((CFieldObject *)descr)->index, |
| 287 | ((CFieldObject *)descr)->offset)) { |
| 288 | Py_DECREF(descr); |
| 289 | Py_DECREF(anon_names); |
| 290 | return -1; |
| 291 | } |
| 292 | Py_DECREF(descr); |
| 293 | } |
Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 294 | |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 295 | Py_DECREF(anon_names); |
| 296 | return 0; |
Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 297 | } |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 298 | |
| 299 | /* |
| 300 | Retrive the (optional) _pack_ attribute from a type, the _fields_ attribute, |
| 301 | and create an StgDictObject. Used for Structure and Union subclasses. |
| 302 | */ |
| 303 | int |
Thomas Heller | 34596a9 | 2009-04-24 20:50:00 +0000 | [diff] [blame] | 304 | PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct) |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 305 | { |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 306 | StgDictObject *stgdict, *basedict; |
| 307 | Py_ssize_t len, offset, size, align, i; |
| 308 | Py_ssize_t union_size, total_align; |
| 309 | Py_ssize_t field_size = 0; |
| 310 | int bitofs; |
| 311 | PyObject *isPacked; |
| 312 | int pack = 0; |
| 313 | Py_ssize_t ffi_ofs; |
| 314 | int big_endian; |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 315 | |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 316 | /* HACK Alert: I cannot be bothered to fix ctypes.com, so there has to |
| 317 | be a way to use the old, broken sematics: _fields_ are not extended |
| 318 | but replaced in subclasses. |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 319 | |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 320 | XXX Remove this in ctypes 1.0! |
| 321 | */ |
| 322 | int use_broken_old_ctypes_semantics; |
| 323 | |
| 324 | if (fields == NULL) |
| 325 | return 0; |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 326 | |
| 327 | #ifdef WORDS_BIGENDIAN |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 328 | big_endian = PyObject_HasAttrString(type, "_swappedbytes_") ? 0 : 1; |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 329 | #else |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 330 | big_endian = PyObject_HasAttrString(type, "_swappedbytes_") ? 1 : 0; |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 331 | #endif |
| 332 | |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 333 | use_broken_old_ctypes_semantics = \ |
| 334 | PyObject_HasAttrString(type, "_use_broken_old_ctypes_structure_semantics_"); |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 335 | |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 336 | isPacked = PyObject_GetAttrString(type, "_pack_"); |
| 337 | if (isPacked) { |
| 338 | pack = PyLong_AsLong(isPacked); |
| 339 | if (pack < 0 || PyErr_Occurred()) { |
| 340 | Py_XDECREF(isPacked); |
| 341 | PyErr_SetString(PyExc_ValueError, |
| 342 | "_pack_ must be a non-negative integer"); |
| 343 | return -1; |
| 344 | } |
| 345 | Py_DECREF(isPacked); |
| 346 | } else |
| 347 | PyErr_Clear(); |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 348 | |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 349 | len = PySequence_Length(fields); |
| 350 | if (len == -1) { |
| 351 | PyErr_SetString(PyExc_TypeError, |
| 352 | "'_fields_' must be a sequence of pairs"); |
| 353 | return -1; |
| 354 | } |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 355 | |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 356 | stgdict = PyType_stgdict(type); |
| 357 | if (!stgdict) |
| 358 | return -1; |
| 359 | /* If this structure/union is already marked final we cannot assign |
| 360 | _fields_ anymore. */ |
Thomas Wouters | 89f507f | 2006-12-13 04:49:30 +0000 | [diff] [blame] | 361 | |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 362 | if (stgdict->flags & DICTFLAG_FINAL) {/* is final ? */ |
| 363 | PyErr_SetString(PyExc_AttributeError, |
| 364 | "_fields_ is final"); |
| 365 | return -1; |
| 366 | } |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 367 | |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 368 | if (stgdict->format) { |
| 369 | PyMem_Free(stgdict->format); |
| 370 | stgdict->format = NULL; |
| 371 | } |
Thomas Heller | b041fda | 2008-04-30 17:11:46 +0000 | [diff] [blame] | 372 | |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 373 | if (stgdict->ffi_type_pointer.elements) |
| 374 | PyMem_Free(stgdict->ffi_type_pointer.elements); |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 375 | |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 376 | basedict = PyType_stgdict((PyObject *)((PyTypeObject *)type)->tp_base); |
| 377 | if (basedict && !use_broken_old_ctypes_semantics) { |
| 378 | size = offset = basedict->size; |
| 379 | align = basedict->align; |
| 380 | union_size = 0; |
| 381 | total_align = align ? align : 1; |
| 382 | stgdict->ffi_type_pointer.type = FFI_TYPE_STRUCT; |
| 383 | stgdict->ffi_type_pointer.elements = PyMem_Malloc(sizeof(ffi_type *) * (basedict->length + len + 1)); |
| 384 | if (stgdict->ffi_type_pointer.elements == NULL) { |
| 385 | PyErr_NoMemory(); |
| 386 | return -1; |
| 387 | } |
| 388 | memset(stgdict->ffi_type_pointer.elements, 0, |
| 389 | sizeof(ffi_type *) * (basedict->length + len + 1)); |
| 390 | memcpy(stgdict->ffi_type_pointer.elements, |
| 391 | basedict->ffi_type_pointer.elements, |
| 392 | sizeof(ffi_type *) * (basedict->length)); |
| 393 | ffi_ofs = basedict->length; |
| 394 | } else { |
| 395 | offset = 0; |
| 396 | size = 0; |
| 397 | align = 0; |
| 398 | union_size = 0; |
| 399 | total_align = 1; |
| 400 | stgdict->ffi_type_pointer.type = FFI_TYPE_STRUCT; |
| 401 | stgdict->ffi_type_pointer.elements = PyMem_Malloc(sizeof(ffi_type *) * (len + 1)); |
| 402 | if (stgdict->ffi_type_pointer.elements == NULL) { |
| 403 | PyErr_NoMemory(); |
| 404 | return -1; |
| 405 | } |
| 406 | memset(stgdict->ffi_type_pointer.elements, 0, |
| 407 | sizeof(ffi_type *) * (len + 1)); |
| 408 | ffi_ofs = 0; |
| 409 | } |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 410 | |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 411 | assert(stgdict->format == NULL); |
| 412 | if (isStruct && !isPacked) { |
| 413 | stgdict->format = _ctypes_alloc_format_string(NULL, "T{"); |
| 414 | } else { |
| 415 | /* PEP3118 doesn't support union, or packed structures (well, |
| 416 | only standard packing, but we dont support the pep for |
| 417 | that). Use 'B' for bytes. */ |
| 418 | stgdict->format = _ctypes_alloc_format_string(NULL, "B"); |
| 419 | } |
Thomas Heller | b041fda | 2008-04-30 17:11:46 +0000 | [diff] [blame] | 420 | |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 421 | #define realdict ((PyObject *)&stgdict->dict) |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 422 | for (i = 0; i < len; ++i) { |
| 423 | PyObject *name = NULL, *desc = NULL; |
| 424 | PyObject *pair = PySequence_GetItem(fields, i); |
| 425 | PyObject *prop; |
| 426 | StgDictObject *dict; |
| 427 | int bitsize = 0; |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 428 | |
Amaury Forgeot d'Arc | 842d921 | 2011-09-02 23:07:54 +0200 | [diff] [blame] | 429 | if (!pair || !PyArg_ParseTuple(pair, "UO|i", &name, &desc, &bitsize)) { |
| 430 | PyErr_SetString(PyExc_TypeError, |
| 431 | "'_fields_' must be a sequence of (name, C type) pairs"); |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 432 | Py_XDECREF(pair); |
| 433 | return -1; |
| 434 | } |
| 435 | dict = PyType_stgdict(desc); |
| 436 | if (dict == NULL) { |
| 437 | Py_DECREF(pair); |
| 438 | PyErr_Format(PyExc_TypeError, |
| 439 | "second item in _fields_ tuple (index %zd) must be a C type", |
| 440 | i); |
| 441 | return -1; |
| 442 | } |
| 443 | stgdict->ffi_type_pointer.elements[ffi_ofs + i] = &dict->ffi_type_pointer; |
| 444 | if (dict->flags & (TYPEFLAG_ISPOINTER | TYPEFLAG_HASPOINTER)) |
| 445 | stgdict->flags |= TYPEFLAG_HASPOINTER; |
| 446 | dict->flags |= DICTFLAG_FINAL; /* mark field type final */ |
| 447 | if (PyTuple_Size(pair) == 3) { /* bits specified */ |
| 448 | switch(dict->ffi_type_pointer.type) { |
| 449 | case FFI_TYPE_UINT8: |
| 450 | case FFI_TYPE_UINT16: |
| 451 | case FFI_TYPE_UINT32: |
| 452 | case FFI_TYPE_SINT64: |
| 453 | case FFI_TYPE_UINT64: |
| 454 | break; |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 455 | |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 456 | case FFI_TYPE_SINT8: |
| 457 | case FFI_TYPE_SINT16: |
| 458 | case FFI_TYPE_SINT32: |
| 459 | if (dict->getfunc != _ctypes_get_fielddesc("c")->getfunc |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 460 | #ifdef CTYPES_UNICODE |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 461 | && dict->getfunc != _ctypes_get_fielddesc("u")->getfunc |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 462 | #endif |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 463 | ) |
| 464 | break; |
| 465 | /* else fall through */ |
| 466 | default: |
| 467 | PyErr_Format(PyExc_TypeError, |
| 468 | "bit fields not allowed for type %s", |
| 469 | ((PyTypeObject *)desc)->tp_name); |
| 470 | Py_DECREF(pair); |
| 471 | return -1; |
| 472 | } |
| 473 | if (bitsize <= 0 || bitsize > dict->size * 8) { |
| 474 | PyErr_SetString(PyExc_ValueError, |
| 475 | "number of bits invalid for bit field"); |
| 476 | Py_DECREF(pair); |
| 477 | return -1; |
| 478 | } |
| 479 | } else |
| 480 | bitsize = 0; |
Amaury Forgeot d'Arc | 842d921 | 2011-09-02 23:07:54 +0200 | [diff] [blame] | 481 | |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 482 | if (isStruct && !isPacked) { |
| 483 | char *fieldfmt = dict->format ? dict->format : "B"; |
| 484 | char *fieldname = _PyUnicode_AsString(name); |
| 485 | char *ptr; |
Amaury Forgeot d'Arc | 02dd539 | 2011-09-02 20:39:40 +0200 | [diff] [blame] | 486 | Py_ssize_t len; |
| 487 | char *buf; |
| 488 | |
| 489 | if (fieldname == NULL) |
| 490 | { |
Amaury Forgeot d'Arc | 02dd539 | 2011-09-02 20:39:40 +0200 | [diff] [blame] | 491 | Py_DECREF(pair); |
| 492 | return -1; |
| 493 | } |
| 494 | |
| 495 | len = strlen(fieldname) + strlen(fieldfmt); |
Thomas Heller | b041fda | 2008-04-30 17:11:46 +0000 | [diff] [blame] | 496 | |
Meador Inge | 1efb33a | 2011-10-03 21:44:22 -0500 | [diff] [blame] | 497 | buf = PyMem_Malloc(len + 2 + 1); |
| 498 | if (buf == NULL) { |
| 499 | Py_DECREF(pair); |
| 500 | PyErr_NoMemory(); |
| 501 | return -1; |
| 502 | } |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 503 | sprintf(buf, "%s:%s:", fieldfmt, fieldname); |
Thomas Heller | b041fda | 2008-04-30 17:11:46 +0000 | [diff] [blame] | 504 | |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 505 | ptr = stgdict->format; |
| 506 | stgdict->format = _ctypes_alloc_format_string(stgdict->format, buf); |
| 507 | PyMem_Free(ptr); |
Meador Inge | 1efb33a | 2011-10-03 21:44:22 -0500 | [diff] [blame] | 508 | PyMem_Free(buf); |
Thomas Heller | b041fda | 2008-04-30 17:11:46 +0000 | [diff] [blame] | 509 | |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 510 | if (stgdict->format == NULL) { |
| 511 | Py_DECREF(pair); |
| 512 | return -1; |
| 513 | } |
| 514 | } |
Amaury Forgeot d'Arc | 842d921 | 2011-09-02 23:07:54 +0200 | [diff] [blame] | 515 | |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 516 | if (isStruct) { |
| 517 | prop = PyCField_FromDesc(desc, i, |
| 518 | &field_size, bitsize, &bitofs, |
| 519 | &size, &offset, &align, |
| 520 | pack, big_endian); |
| 521 | } else /* union */ { |
| 522 | size = 0; |
| 523 | offset = 0; |
| 524 | align = 0; |
| 525 | prop = PyCField_FromDesc(desc, i, |
| 526 | &field_size, bitsize, &bitofs, |
| 527 | &size, &offset, &align, |
| 528 | pack, big_endian); |
| 529 | union_size = max(size, union_size); |
| 530 | } |
| 531 | total_align = max(align, total_align); |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 532 | |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 533 | if (!prop) { |
| 534 | Py_DECREF(pair); |
| 535 | return -1; |
| 536 | } |
| 537 | if (-1 == PyObject_SetAttr(type, name, prop)) { |
| 538 | Py_DECREF(prop); |
| 539 | Py_DECREF(pair); |
| 540 | return -1; |
| 541 | } |
| 542 | Py_DECREF(pair); |
| 543 | Py_DECREF(prop); |
| 544 | } |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 545 | #undef realdict |
Thomas Heller | b041fda | 2008-04-30 17:11:46 +0000 | [diff] [blame] | 546 | |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 547 | if (isStruct && !isPacked) { |
| 548 | char *ptr = stgdict->format; |
| 549 | stgdict->format = _ctypes_alloc_format_string(stgdict->format, "}"); |
| 550 | PyMem_Free(ptr); |
| 551 | if (stgdict->format == NULL) |
| 552 | return -1; |
| 553 | } |
Thomas Heller | b041fda | 2008-04-30 17:11:46 +0000 | [diff] [blame] | 554 | |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 555 | if (!isStruct) |
| 556 | size = union_size; |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 557 | |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 558 | /* Adjust the size according to the alignment requirements */ |
| 559 | size = ((size + total_align - 1) / total_align) * total_align; |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 560 | |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 561 | stgdict->ffi_type_pointer.alignment = Py_SAFE_DOWNCAST(total_align, |
| 562 | Py_ssize_t, |
| 563 | unsigned short); |
| 564 | stgdict->ffi_type_pointer.size = size; |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 565 | |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 566 | stgdict->size = size; |
| 567 | stgdict->align = total_align; |
| 568 | stgdict->length = len; /* ADD ffi_ofs? */ |
Thomas Wouters | 89f507f | 2006-12-13 04:49:30 +0000 | [diff] [blame] | 569 | |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 570 | /* We did check that this flag was NOT set above, it must not |
| 571 | have been set until now. */ |
| 572 | if (stgdict->flags & DICTFLAG_FINAL) { |
| 573 | PyErr_SetString(PyExc_AttributeError, |
| 574 | "Structure or union cannot contain itself"); |
| 575 | return -1; |
| 576 | } |
| 577 | stgdict->flags |= DICTFLAG_FINAL; |
Thomas Wouters | 89f507f | 2006-12-13 04:49:30 +0000 | [diff] [blame] | 578 | |
Antoine Pitrou | f95a1b3 | 2010-05-09 15:52:27 +0000 | [diff] [blame] | 579 | return MakeAnonFields(type); |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 580 | } |