1 /*****************************************************************
2 This file should be kept compatible with Python 2.3, see PEP 291.
3 *****************************************************************/
12 /******************************************************************/
14 StdDict - a dictionary subclass, containing additional C accessible fields
19 /* Seems we need this, otherwise we get problems when calling
20 * PyDict_SetItem() (ma_lookup is NULL)
23 StgDict_init(StgDictObject
*self
, PyObject
*args
, PyObject
*kwds
)
25 if (PyDict_Type
.tp_init((PyObject
*)self
, args
, kwds
) < 0)
31 StgDict_clear(StgDictObject
*self
)
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
);
42 StgDict_dealloc(StgDictObject
*self
)
45 PyMem_Free(self
->ffi_type_pointer
.elements
);
46 PyDict_Type
.tp_dealloc((PyObject
*)self
);
50 StgDict_clone(StgDictObject
*dst
, StgDictObject
*src
)
56 PyMem_Free(dst
->ffi_type_pointer
.elements
);
57 dst
->ffi_type_pointer
.elements
= NULL
;
61 memcpy(d
+ sizeof(PyDictObject
),
62 s
+ sizeof(PyDictObject
),
63 sizeof(StgDictObject
) - sizeof(PyDictObject
));
65 Py_XINCREF(dst
->proto
);
66 Py_XINCREF(dst
->argtypes
);
67 Py_XINCREF(dst
->converters
);
68 Py_XINCREF(dst
->restype
);
69 Py_XINCREF(dst
->checker
);
71 if (src
->ffi_type_pointer
.elements
== NULL
)
73 size
= sizeof(ffi_type
*) * (src
->length
+ 1);
74 dst
->ffi_type_pointer
.elements
= PyMem_Malloc(size
);
75 if (dst
->ffi_type_pointer
.elements
== NULL
)
77 memcpy(dst
->ffi_type_pointer
.elements
,
78 src
->ffi_type_pointer
.elements
,
83 PyTypeObject StgDict_Type
= {
84 PyObject_HEAD_INIT(NULL
)
87 sizeof(StgDictObject
),
89 (destructor
)StgDict_dealloc
, /* tp_dealloc */
96 0, /* tp_as_sequence */
97 0, /* tp_as_mapping */
103 0, /* tp_as_buffer */
104 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
, /* tp_flags */
108 0, /* tp_richcompare */
109 0, /* tp_weaklistoffset */
117 0, /* tp_descr_get */
118 0, /* tp_descr_set */
119 0, /* tp_dictoffset */
120 (initproc
)StgDict_init
, /* tp_init */
126 /* May return NULL, but does not set an exception! */
128 PyType_stgdict(PyObject
*obj
)
132 if (!PyType_Check(obj
))
134 type
= (PyTypeObject
*)obj
;
135 if (!PyType_HasFeature(type
, Py_TPFLAGS_HAVE_CLASS
))
137 if (!type
->tp_dict
|| !StgDict_CheckExact(type
->tp_dict
))
139 return (StgDictObject
*)type
->tp_dict
;
142 /* May return NULL, but does not set an exception! */
144 This function should be as fast as possible, so we don't call PyType_stgdict
145 above but inline the code, and avoid the PyType_Check().
148 PyObject_stgdict(PyObject
*self
)
150 PyTypeObject
*type
= self
->ob_type
;
151 if (!PyType_HasFeature(type
, Py_TPFLAGS_HAVE_CLASS
))
153 if (!type
->tp_dict
|| !StgDict_CheckExact(type
->tp_dict
))
155 return (StgDictObject
*)type
->tp_dict
;
158 /* descr is the descriptor for a field marked as anonymous. Get all the
159 _fields_ descriptors from descr->proto, create new descriptors with offset
160 and index adjusted, and stuff them into type.
163 MakeFields(PyObject
*type
, CFieldObject
*descr
,
164 Py_ssize_t index
, Py_ssize_t offset
)
170 fields
= PyObject_GetAttrString(descr
->proto
, "_fields_");
173 fieldlist
= PySequence_Fast(fields
, "_fields_ must be a sequence");
175 if (fieldlist
== NULL
)
178 for (i
= 0; i
< PySequence_Fast_GET_SIZE(fieldlist
); ++i
) {
179 PyObject
*pair
= PySequence_Fast_GET_ITEM(fieldlist
, i
); /* borrowed */
180 PyObject
*fname
, *ftype
, *bits
;
181 CFieldObject
*fdescr
;
182 CFieldObject
*new_descr
;
183 /* Convert to PyArg_UnpackTuple... */
184 if (!PyArg_ParseTuple(pair
, "OO|O", &fname
, &ftype
, &bits
)) {
185 Py_DECREF(fieldlist
);
188 fdescr
= (CFieldObject
*)PyObject_GetAttr(descr
->proto
, fname
);
189 if (fdescr
== NULL
) {
190 Py_DECREF(fieldlist
);
193 if (fdescr
->ob_type
!= &CField_Type
) {
194 PyErr_SetString(PyExc_TypeError
, "unexpected type");
196 Py_DECREF(fieldlist
);
199 if (fdescr
->anonymous
) {
200 int rc
= MakeFields(type
, fdescr
,
201 index
+ fdescr
->index
,
202 offset
+ fdescr
->offset
);
205 Py_DECREF(fieldlist
);
210 new_descr
= (CFieldObject
*)PyObject_CallObject((PyObject
*)&CField_Type
, NULL
);
211 if (new_descr
== NULL
) {
213 Py_DECREF(fieldlist
);
216 assert(new_descr
->ob_type
== &CField_Type
);
217 new_descr
->size
= fdescr
->size
;
218 new_descr
->offset
= fdescr
->offset
+ offset
;
219 new_descr
->index
= fdescr
->index
+ index
;
220 new_descr
->proto
= fdescr
->proto
;
221 Py_XINCREF(new_descr
->proto
);
222 new_descr
->getfunc
= fdescr
->getfunc
;
223 new_descr
->setfunc
= fdescr
->setfunc
;
227 if (-1 == PyObject_SetAttr(type
, fname
, (PyObject
*)new_descr
)) {
228 Py_DECREF(fieldlist
);
229 Py_DECREF(new_descr
);
232 Py_DECREF(new_descr
);
234 Py_DECREF(fieldlist
);
238 /* Iterate over the names in the type's _anonymous_ attribute, if present,
241 MakeAnonFields(PyObject
*type
)
244 PyObject
*anon_names
;
247 anon
= PyObject_GetAttrString(type
, "_anonymous_");
252 anon_names
= PySequence_Fast(anon
, "_anonymous_ must be a sequence");
254 if (anon_names
== NULL
)
257 for (i
= 0; i
< PySequence_Fast_GET_SIZE(anon_names
); ++i
) {
258 PyObject
*fname
= PySequence_Fast_GET_ITEM(anon_names
, i
); /* borrowed */
259 CFieldObject
*descr
= (CFieldObject
*)PyObject_GetAttr(type
, fname
);
261 Py_DECREF(anon_names
);
264 assert(descr
->ob_type
== &CField_Type
);
265 descr
->anonymous
= 1;
267 /* descr is in the field descriptor. */
268 if (-1 == MakeFields(type
, (CFieldObject
*)descr
,
269 ((CFieldObject
*)descr
)->index
,
270 ((CFieldObject
*)descr
)->offset
)) {
272 Py_DECREF(anon_names
);
278 Py_DECREF(anon_names
);
283 Retrive the (optional) _pack_ attribute from a type, the _fields_ attribute,
284 and create an StgDictObject. Used for Structure and Union subclasses.
287 StructUnionType_update_stgdict(PyObject
*type
, PyObject
*fields
, int isStruct
)
289 StgDictObject
*stgdict
, *basedict
;
290 int len
, offset
, size
, align
, i
;
291 int union_size
, total_align
;
299 /* HACK Alert: I cannot be bothered to fix ctypes.com, so there has to
300 be a way to use the old, broken sematics: _fields_ are not extended
301 but replaced in subclasses.
303 XXX Remove this in ctypes 1.0!
305 int use_broken_old_ctypes_semantics
;
310 #ifdef WORDS_BIGENDIAN
311 big_endian
= PyObject_HasAttrString(type
, "_swappedbytes_") ? 0 : 1;
313 big_endian
= PyObject_HasAttrString(type
, "_swappedbytes_") ? 1 : 0;
316 use_broken_old_ctypes_semantics
= \
317 PyObject_HasAttrString(type
, "_use_broken_old_ctypes_structure_semantics_");
319 isPacked
= PyObject_GetAttrString(type
, "_pack_");
321 pack
= PyInt_AsLong(isPacked
);
322 if (pack
< 0 || PyErr_Occurred()) {
323 Py_XDECREF(isPacked
);
324 PyErr_SetString(PyExc_ValueError
,
325 "_pack_ must be a non-negative integer");
332 len
= PySequence_Length(fields
);
334 PyErr_SetString(PyExc_TypeError
,
335 "'_fields_' must be a sequence of pairs");
339 stgdict
= PyType_stgdict(type
);
342 /* If this structure/union is already marked final we cannot assign
345 if (stgdict
->flags
& DICTFLAG_FINAL
) {/* is final ? */
346 PyErr_SetString(PyExc_AttributeError
,
347 "_fields_ is final");
351 if (stgdict
->ffi_type_pointer
.elements
)
352 PyMem_Free(stgdict
->ffi_type_pointer
.elements
);
354 basedict
= PyType_stgdict((PyObject
*)((PyTypeObject
*)type
)->tp_base
);
355 if (basedict
&& !use_broken_old_ctypes_semantics
) {
356 size
= offset
= basedict
->size
;
357 align
= basedict
->align
;
359 total_align
= align
? align
: 1;
360 stgdict
->ffi_type_pointer
.type
= FFI_TYPE_STRUCT
;
361 stgdict
->ffi_type_pointer
.elements
= PyMem_Malloc(sizeof(ffi_type
*) * (basedict
->length
+ len
+ 1));
362 memset(stgdict
->ffi_type_pointer
.elements
, 0,
363 sizeof(ffi_type
*) * (basedict
->length
+ len
+ 1));
364 memcpy(stgdict
->ffi_type_pointer
.elements
,
365 basedict
->ffi_type_pointer
.elements
,
366 sizeof(ffi_type
*) * (basedict
->length
));
367 ffi_ofs
= basedict
->length
;
374 stgdict
->ffi_type_pointer
.type
= FFI_TYPE_STRUCT
;
375 stgdict
->ffi_type_pointer
.elements
= PyMem_Malloc(sizeof(ffi_type
*) * (len
+ 1));
376 memset(stgdict
->ffi_type_pointer
.elements
, 0,
377 sizeof(ffi_type
*) * (len
+ 1));
381 #define realdict ((PyObject *)&stgdict->dict)
382 for (i
= 0; i
< len
; ++i
) {
383 PyObject
*name
= NULL
, *desc
= NULL
;
384 PyObject
*pair
= PySequence_GetItem(fields
, i
);
389 if (!pair
|| !PyArg_ParseTuple(pair
, "OO|i", &name
, &desc
, &bitsize
)) {
390 PyErr_SetString(PyExc_AttributeError
,
391 "'_fields_' must be a sequence of pairs");
395 dict
= PyType_stgdict(desc
);
398 PyErr_Format(PyExc_TypeError
,
399 "second item in _fields_ tuple (index %d) must be a C type",
403 stgdict
->ffi_type_pointer
.elements
[ffi_ofs
+ i
] = &dict
->ffi_type_pointer
;
404 dict
->flags
|= DICTFLAG_FINAL
; /* mark field type final */
405 if (PyTuple_Size(pair
) == 3) { /* bits specified */
406 switch(dict
->ffi_type_pointer
.type
) {
408 case FFI_TYPE_UINT16
:
409 case FFI_TYPE_UINT32
:
410 case FFI_TYPE_SINT64
:
411 case FFI_TYPE_UINT64
:
415 case FFI_TYPE_SINT16
:
416 case FFI_TYPE_SINT32
:
417 if (dict
->getfunc
!= getentry("c")->getfunc
418 #ifdef CTYPES_UNICODE
419 && dict
->getfunc
!= getentry("u")->getfunc
423 /* else fall through */
425 PyErr_Format(PyExc_TypeError
,
426 "bit fields not allowed for type %s",
427 ((PyTypeObject
*)desc
)->tp_name
);
431 if (bitsize
<= 0 || bitsize
> dict
->size
* 8) {
432 PyErr_SetString(PyExc_ValueError
,
433 "number of bits invalid for bit field");
440 prop
= CField_FromDesc(desc
, i
,
441 &field_size
, bitsize
, &bitofs
,
442 &size
, &offset
, &align
,
448 prop
= CField_FromDesc(desc
, i
,
449 &field_size
, bitsize
, &bitofs
,
450 &size
, &offset
, &align
,
452 union_size
= max(size
, union_size
);
454 total_align
= max(align
, total_align
);
458 Py_DECREF((PyObject
*)stgdict
);
461 if (-1 == PyDict_SetItem(realdict
, name
, prop
)) {
464 Py_DECREF((PyObject
*)stgdict
);
474 /* Adjust the size according to the alignment requirements */
475 size
= ((size
+ total_align
- 1) / total_align
) * total_align
;
477 stgdict
->ffi_type_pointer
.alignment
= total_align
;
478 stgdict
->ffi_type_pointer
.size
= size
;
480 stgdict
->size
= size
;
481 stgdict
->align
= total_align
;
482 stgdict
->length
= len
; /* ADD ffi_ofs? */
484 /* We did check that this flag was NOT set above, it must not
485 have been set until now. */
486 if (stgdict
->flags
& DICTFLAG_FINAL
) {
487 PyErr_SetString(PyExc_AttributeError
,
488 "Structure or union cannot contain itself");
491 stgdict
->flags
|= DICTFLAG_FINAL
;
493 return MakeAnonFields(type
);