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