PageRenderTime 1092ms CodeModel.GetById 765ms app.highlight 141ms RepoModel.GetById 180ms app.codeStats 1ms

/Modules/_ctypes/stgdict.c

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