/Modules/_ctypes/_ctypes.c
http://unladen-swallow.googlecode.com/ · C · 5688 lines · 4503 code · 562 blank · 623 comment · 878 complexity · 7a1aa045f181b16031ab55b50d942c59 MD5 · raw file
Large files are truncated click here to view the full file
- /*****************************************************************
- This file should be kept compatible with Python 2.3, see PEP 291.
- *****************************************************************/
- /*
- ToDo:
- Get rid of the checker (and also the converters) field in CFuncPtrObject and
- StgDictObject, and replace them by slot functions in StgDictObject.
- think about a buffer-like object (memory? bytes?)
- Should POINTER(c_char) and POINTER(c_wchar) have a .value property?
- What about c_char and c_wchar arrays then?
- Add from_mmap, from_file, from_string metaclass methods.
- Maybe we can get away with from_file (calls read) and with a from_buffer
- method?
- And what about the to_mmap, to_file, to_str(?) methods? They would clobber
- the namespace, probably. So, functions instead? And we already have memmove...
- */
- /*
- Name methods, members, getsets
- ==============================================================================
- StructType_Type __new__(), from_address(), __mul__(), from_param()
- UnionType_Type __new__(), from_address(), __mul__(), from_param()
- PointerType_Type __new__(), from_address(), __mul__(), from_param(), set_type()
- ArrayType_Type __new__(), from_address(), __mul__(), from_param()
- SimpleType_Type __new__(), from_address(), __mul__(), from_param()
- CData_Type
- Struct_Type __new__(), __init__()
- Pointer_Type __new__(), __init__(), _as_parameter_, contents
- Array_Type __new__(), __init__(), _as_parameter_, __get/setitem__(), __len__()
- Simple_Type __new__(), __init__(), _as_parameter_
- CField_Type
- StgDict_Type
- ==============================================================================
- class methods
- -------------
- It has some similarity to the byref() construct compared to pointer()
- from_address(addr)
- - construct an instance from a given memory block (sharing this memory block)
- from_param(obj)
- - typecheck and convert a Python object into a C function call parameter
- the result may be an instance of the type, or an integer or tuple
- (typecode, value[, obj])
- instance methods/properties
- ---------------------------
- _as_parameter_
- - convert self into a C function call parameter
- This is either an integer, or a 3-tuple (typecode, value, obj)
- functions
- ---------
- sizeof(cdata)
- - return the number of bytes the buffer contains
- sizeof(ctype)
- - return the number of bytes the buffer of an instance would contain
- byref(cdata)
- addressof(cdata)
- pointer(cdata)
- POINTER(ctype)
- bytes(cdata)
- - return the buffer contents as a sequence of bytes (which is currently a string)
- */
- /*
- * StgDict_Type
- * StructType_Type
- * UnionType_Type
- * PointerType_Type
- * ArrayType_Type
- * SimpleType_Type
- *
- * CData_Type
- * Struct_Type
- * Union_Type
- * Array_Type
- * Simple_Type
- * Pointer_Type
- * CField_Type
- *
- */
- #define PY_SSIZE_T_CLEAN
- #include "Python.h"
- #include "structmember.h"
- #include <ffi.h>
- #ifdef MS_WIN32
- #include <windows.h>
- #include <malloc.h>
- #ifndef IS_INTRESOURCE
- #define IS_INTRESOURCE(x) (((size_t)(x) >> 16) == 0)
- #endif
- # ifdef _WIN32_WCE
- /* Unlike desktop Windows, WinCE has both W and A variants of
- GetProcAddress, but the default W version is not what we want */
- # undef GetProcAddress
- # define GetProcAddress GetProcAddressA
- # endif
- #else
- #include "ctypes_dlfcn.h"
- #endif
- #include "ctypes.h"
- PyObject *PyExc_ArgError;
- /* This dict maps ctypes types to POINTER types */
- PyObject *_pointer_type_cache;
- static PyTypeObject Simple_Type;
- /* a callable object used for unpickling */
- static PyObject *_unpickle;
- char *conversion_mode_encoding = NULL;
- char *conversion_mode_errors = NULL;
- /****************************************************************/
- #if (PY_VERSION_HEX < 0x02040000)
- /* Only in Python 2.4 and up */
- static PyObject *
- PyTuple_Pack(int n, ...)
- {
- int i;
- PyObject *o;
- PyObject *result;
- PyObject **items;
- va_list vargs;
- va_start(vargs, n);
- result = PyTuple_New(n);
- if (result == NULL)
- return NULL;
- items = ((PyTupleObject *)result)->ob_item;
- for (i = 0; i < n; i++) {
- o = va_arg(vargs, PyObject *);
- Py_INCREF(o);
- items[i] = o;
- }
- va_end(vargs);
- return result;
- }
- #endif
- /****************************************************************/
- typedef struct {
- PyObject_HEAD
- PyObject *key;
- PyObject *dict;
- } DictRemoverObject;
- static void
- _DictRemover_dealloc(PyObject *_self)
- {
- DictRemoverObject *self = (DictRemoverObject *)_self;
- Py_XDECREF(self->key);
- Py_XDECREF(self->dict);
- Py_TYPE(self)->tp_free(_self);
- }
- static PyObject *
- _DictRemover_call(PyObject *_self, PyObject *args, PyObject *kw)
- {
- DictRemoverObject *self = (DictRemoverObject *)_self;
- if (self->key && self->dict) {
- if (-1 == PyDict_DelItem(self->dict, self->key))
- /* XXX Error context */
- PyErr_WriteUnraisable(Py_None);
- Py_DECREF(self->key);
- self->key = NULL;
- Py_DECREF(self->dict);
- self->dict = NULL;
- }
- Py_INCREF(Py_None);
- return Py_None;
- }
- static PyTypeObject DictRemover_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "_ctypes.DictRemover", /* tp_name */
- sizeof(DictRemoverObject), /* tp_basicsize */
- 0, /* tp_itemsize */
- _DictRemover_dealloc, /* tp_dealloc */
- 0, /* tp_print */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_compare */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- _DictRemover_call, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- /* XXX should participate in GC? */
- Py_TPFLAGS_DEFAULT, /* tp_flags */
- "deletes a key from a dictionary", /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- 0, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- 0, /* tp_init */
- 0, /* tp_alloc */
- 0, /* tp_new */
- 0, /* tp_free */
- };
- int
- PyDict_SetItemProxy(PyObject *dict, PyObject *key, PyObject *item)
- {
- PyObject *obj;
- DictRemoverObject *remover;
- PyObject *proxy;
- int result;
- obj = PyObject_CallObject((PyObject *)&DictRemover_Type, NULL);
- if (obj == NULL)
- return -1;
- remover = (DictRemoverObject *)obj;
- assert(remover->key == NULL);
- assert(remover->dict == NULL);
- Py_INCREF(key);
- remover->key = key;
- Py_INCREF(dict);
- remover->dict = dict;
- proxy = PyWeakref_NewProxy(item, obj);
- Py_DECREF(obj);
- if (proxy == NULL)
- return -1;
- result = PyDict_SetItem(dict, key, proxy);
- Py_DECREF(proxy);
- return result;
- }
- PyObject *
- PyDict_GetItemProxy(PyObject *dict, PyObject *key)
- {
- PyObject *result;
- PyObject *item = PyDict_GetItem(dict, key);
- if (item == NULL)
- return NULL;
- if (!PyWeakref_CheckProxy(item))
- return item;
- result = PyWeakref_GET_OBJECT(item);
- if (result == Py_None)
- return NULL;
- return result;
- }
- /******************************************************************/
- /*
- Allocate a memory block for a pep3118 format string, copy prefix (if
- non-null) and suffix into it. Returns NULL on failure, with the error
- indicator set. If called with a suffix of NULL the error indicator must
- already be set.
- */
- char *
- alloc_format_string(const char *prefix, const char *suffix)
- {
- size_t len;
- char *result;
- if (suffix == NULL) {
- assert(PyErr_Occurred());
- return NULL;
- }
- len = strlen(suffix);
- if (prefix)
- len += strlen(prefix);
- result = PyMem_Malloc(len + 1);
- if (result == NULL)
- return NULL;
- if (prefix)
- strcpy(result, prefix);
- else
- result[0] = '\0';
- strcat(result, suffix);
- return result;
- }
- /*
- StructType_Type - a meta type/class. Creating a new class using this one as
- __metaclass__ will call the contructor StructUnionType_new. It replaces the
- tp_dict member with a new instance of StgDict, and initializes the C
- accessible fields somehow.
- */
- static PyCArgObject *
- StructUnionType_paramfunc(CDataObject *self)
- {
- PyCArgObject *parg;
- StgDictObject *stgdict;
-
- parg = new_CArgObject();
- if (parg == NULL)
- return NULL;
- parg->tag = 'V';
- stgdict = PyObject_stgdict((PyObject *)self);
- assert(stgdict); /* Cannot be NULL for structure/union instances */
- parg->pffi_type = &stgdict->ffi_type_pointer;
- /* For structure parameters (by value), parg->value doesn't contain the structure
- data itself, instead parg->value.p *points* to the structure's data
- See also _ctypes.c, function _call_function_pointer().
- */
- parg->value.p = self->b_ptr;
- parg->size = self->b_size;
- Py_INCREF(self);
- parg->obj = (PyObject *)self;
- return parg;
- }
- static PyObject *
- StructUnionType_new(PyTypeObject *type, PyObject *args, PyObject *kwds, int isStruct)
- {
- PyTypeObject *result;
- PyObject *fields;
- StgDictObject *dict;
- /* create the new instance (which is a class,
- since we are a metatype!) */
- result = (PyTypeObject *)PyType_Type.tp_new(type, args, kwds);
- if (!result)
- return NULL;
- /* keep this for bw compatibility */
- if (PyDict_GetItemString(result->tp_dict, "_abstract_"))
- return (PyObject *)result;
- dict = (StgDictObject *)PyObject_CallObject((PyObject *)&StgDict_Type, NULL);
- if (!dict) {
- Py_DECREF(result);
- return NULL;
- }
- /* replace the class dict by our updated stgdict, which holds info
- about storage requirements of the instances */
- if (-1 == PyDict_Update((PyObject *)dict, result->tp_dict)) {
- Py_DECREF(result);
- Py_DECREF((PyObject *)dict);
- return NULL;
- }
- Py_DECREF(result->tp_dict);
- result->tp_dict = (PyObject *)dict;
- dict->format = alloc_format_string(NULL, "B");
- if (dict->format == NULL) {
- Py_DECREF(result);
- return NULL;
- }
- dict->paramfunc = StructUnionType_paramfunc;
- fields = PyDict_GetItemString((PyObject *)dict, "_fields_");
- if (!fields) {
- StgDictObject *basedict = PyType_stgdict((PyObject *)result->tp_base);
- if (basedict == NULL)
- return (PyObject *)result;
- /* copy base dict */
- if (-1 == StgDict_clone(dict, basedict)) {
- Py_DECREF(result);
- return NULL;
- }
- dict->flags &= ~DICTFLAG_FINAL; /* clear the 'final' flag in the subclass dict */
- basedict->flags |= DICTFLAG_FINAL; /* set the 'final' flag in the baseclass dict */
- return (PyObject *)result;
- }
- if (-1 == PyObject_SetAttrString((PyObject *)result, "_fields_", fields)) {
- Py_DECREF(result);
- return NULL;
- }
- return (PyObject *)result;
- }
- static PyObject *
- StructType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
- {
- return StructUnionType_new(type, args, kwds, 1);
- }
- static PyObject *
- UnionType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
- {
- return StructUnionType_new(type, args, kwds, 0);
- }
- static char from_address_doc[] =
- "C.from_address(integer) -> C instance\naccess a C instance at the specified address";
- static PyObject *
- CDataType_from_address(PyObject *type, PyObject *value)
- {
- void *buf;
- if (!PyInt_Check(value) && !PyLong_Check(value)) {
- PyErr_SetString(PyExc_TypeError,
- "integer expected");
- return NULL;
- }
- buf = (void *)PyLong_AsVoidPtr(value);
- if (PyErr_Occurred())
- return NULL;
- return CData_AtAddress(type, buf);
- }
- static char from_buffer_doc[] =
- "C.from_buffer(object, offset=0) -> C instance\ncreate a C instance from a writeable buffer";
- static int
- KeepRef(CDataObject *target, Py_ssize_t index, PyObject *keep);
- static PyObject *
- CDataType_from_buffer(PyObject *type, PyObject *args)
- {
- void *buffer;
- Py_ssize_t buffer_len;
- Py_ssize_t offset = 0;
- PyObject *obj, *result;
- StgDictObject *dict = PyType_stgdict(type);
- assert (dict);
- if (!PyArg_ParseTuple(args,
- #if (PY_VERSION_HEX < 0x02050000)
- "O|i:from_buffer",
- #else
- "O|n:from_buffer",
- #endif
- &obj, &offset))
- return NULL;
- if (-1 == PyObject_AsWriteBuffer(obj, &buffer, &buffer_len))
- return NULL;
- if (offset < 0) {
- PyErr_SetString(PyExc_ValueError,
- "offset cannot be negative");
- return NULL;
- }
- if (dict->size > buffer_len - offset) {
- PyErr_Format(PyExc_ValueError,
- #if (PY_VERSION_HEX < 0x02050000)
- "Buffer size too small (%d instead of at least %d bytes)",
- #else
- "Buffer size too small (%zd instead of at least %zd bytes)",
- #endif
- buffer_len, dict->size + offset);
- return NULL;
- }
- result = CData_AtAddress(type, (char *)buffer + offset);
- if (result == NULL)
- return NULL;
- Py_INCREF(obj);
- if (-1 == KeepRef((CDataObject *)result, -1, obj)) {
- Py_DECREF(result);
- return NULL;
- }
- return result;
- }
- static char from_buffer_copy_doc[] =
- "C.from_buffer_copy(object, offset=0) -> C instance\ncreate a C instance from a readable buffer";
- static PyObject *
- GenericCData_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
- static PyObject *
- CDataType_from_buffer_copy(PyObject *type, PyObject *args)
- {
- const void *buffer;
- Py_ssize_t buffer_len;
- Py_ssize_t offset = 0;
- PyObject *obj, *result;
- StgDictObject *dict = PyType_stgdict(type);
- assert (dict);
- if (!PyArg_ParseTuple(args,
- #if (PY_VERSION_HEX < 0x02050000)
- "O|i:from_buffer",
- #else
- "O|n:from_buffer",
- #endif
- &obj, &offset))
- return NULL;
- if (-1 == PyObject_AsReadBuffer(obj, &buffer, &buffer_len))
- return NULL;
- if (offset < 0) {
- PyErr_SetString(PyExc_ValueError,
- "offset cannot be negative");
- return NULL;
- }
- if (dict->size > buffer_len - offset) {
- PyErr_Format(PyExc_ValueError,
- #if (PY_VERSION_HEX < 0x02050000)
- "Buffer size too small (%d instead of at least %d bytes)",
- #else
- "Buffer size too small (%zd instead of at least %zd bytes)",
- #endif
- buffer_len, dict->size + offset);
- return NULL;
- }
- result = GenericCData_new((PyTypeObject *)type, NULL, NULL);
- if (result == NULL)
- return NULL;
- memcpy(((CDataObject *)result)->b_ptr,
- (char *)buffer+offset, dict->size);
- return result;
- }
- static char in_dll_doc[] =
- "C.in_dll(dll, name) -> C instance\naccess a C instance in a dll";
- static PyObject *
- CDataType_in_dll(PyObject *type, PyObject *args)
- {
- PyObject *dll;
- char *name;
- PyObject *obj;
- void *handle;
- void *address;
- if (!PyArg_ParseTuple(args, "Os:in_dll", &dll, &name))
- return NULL;
- obj = PyObject_GetAttrString(dll, "_handle");
- if (!obj)
- return NULL;
- if (!PyInt_Check(obj) && !PyLong_Check(obj)) {
- PyErr_SetString(PyExc_TypeError,
- "the _handle attribute of the second argument must be an integer");
- Py_DECREF(obj);
- return NULL;
- }
- handle = (void *)PyLong_AsVoidPtr(obj);
- Py_DECREF(obj);
- if (PyErr_Occurred()) {
- PyErr_SetString(PyExc_ValueError,
- "could not convert the _handle attribute to a pointer");
- return NULL;
- }
- #ifdef MS_WIN32
- address = (void *)GetProcAddress(handle, name);
- if (!address) {
- PyErr_Format(PyExc_ValueError,
- "symbol '%s' not found",
- name);
- return NULL;
- }
- #else
- address = (void *)ctypes_dlsym(handle, name);
- if (!address) {
- #ifdef __CYGWIN__
- /* dlerror() isn't very helpful on cygwin */
- PyErr_Format(PyExc_ValueError,
- "symbol '%s' not found (%s) ",
- name);
- #else
- PyErr_SetString(PyExc_ValueError, ctypes_dlerror());
- #endif
- return NULL;
- }
- #endif
- return CData_AtAddress(type, address);
- }
- static char from_param_doc[] =
- "Convert a Python object into a function call parameter.";
- static PyObject *
- CDataType_from_param(PyObject *type, PyObject *value)
- {
- PyObject *as_parameter;
- if (1 == PyObject_IsInstance(value, type)) {
- Py_INCREF(value);
- return value;
- }
- if (PyCArg_CheckExact(value)) {
- PyCArgObject *p = (PyCArgObject *)value;
- PyObject *ob = p->obj;
- const char *ob_name;
- StgDictObject *dict;
- dict = PyType_stgdict(type);
- /* If we got a PyCArgObject, we must check if the object packed in it
- is an instance of the type's dict->proto */
- if(dict && ob
- && PyObject_IsInstance(ob, dict->proto)) {
- Py_INCREF(value);
- return value;
- }
- ob_name = (ob) ? Py_TYPE(ob)->tp_name : "???";
- PyErr_Format(PyExc_TypeError,
- "expected %s instance instead of pointer to %s",
- ((PyTypeObject *)type)->tp_name, ob_name);
- return NULL;
- }
- as_parameter = PyObject_GetAttrString(value, "_as_parameter_");
- if (as_parameter) {
- value = CDataType_from_param(type, as_parameter);
- Py_DECREF(as_parameter);
- return value;
- }
- PyErr_Format(PyExc_TypeError,
- "expected %s instance instead of %s",
- ((PyTypeObject *)type)->tp_name,
- Py_TYPE(value)->tp_name);
- return NULL;
- }
- static PyMethodDef CDataType_methods[] = {
- { "from_param", CDataType_from_param, METH_O, from_param_doc },
- { "from_address", CDataType_from_address, METH_O, from_address_doc },
- { "from_buffer", CDataType_from_buffer, METH_VARARGS, from_buffer_doc, },
- { "from_buffer_copy", CDataType_from_buffer_copy, METH_VARARGS, from_buffer_copy_doc, },
- { "in_dll", CDataType_in_dll, METH_VARARGS, in_dll_doc },
- { NULL, NULL },
- };
- static PyObject *
- CDataType_repeat(PyObject *self, Py_ssize_t length)
- {
- if (length < 0)
- return PyErr_Format(PyExc_ValueError,
- #if (PY_VERSION_HEX < 0x02050000)
- "Array length must be >= 0, not %d",
- #else
- "Array length must be >= 0, not %zd",
- #endif
- length);
- return CreateArrayType(self, length);
- }
- static PySequenceMethods CDataType_as_sequence = {
- 0, /* inquiry sq_length; */
- 0, /* binaryfunc sq_concat; */
- CDataType_repeat, /* intargfunc sq_repeat; */
- 0, /* intargfunc sq_item; */
- 0, /* intintargfunc sq_slice; */
- 0, /* intobjargproc sq_ass_item; */
- 0, /* intintobjargproc sq_ass_slice; */
- 0, /* objobjproc sq_contains; */
-
- 0, /* binaryfunc sq_inplace_concat; */
- 0, /* intargfunc sq_inplace_repeat; */
- };
- static int
- CDataType_clear(PyTypeObject *self)
- {
- StgDictObject *dict = PyType_stgdict((PyObject *)self);
- if (dict)
- Py_CLEAR(dict->proto);
- return PyType_Type.tp_clear((PyObject *)self);
- }
- static int
- CDataType_traverse(PyTypeObject *self, visitproc visit, void *arg)
- {
- StgDictObject *dict = PyType_stgdict((PyObject *)self);
- if (dict)
- Py_VISIT(dict->proto);
- return PyType_Type.tp_traverse((PyObject *)self, visit, arg);
- }
- static int
- StructType_setattro(PyObject *self, PyObject *key, PyObject *value)
- {
- /* XXX Should we disallow deleting _fields_? */
- if (-1 == PyType_Type.tp_setattro(self, key, value))
- return -1;
-
- if (value && PyString_Check(key) &&
- 0 == strcmp(PyString_AS_STRING(key), "_fields_"))
- return StructUnionType_update_stgdict(self, value, 1);
- return 0;
- }
- static int
- UnionType_setattro(PyObject *self, PyObject *key, PyObject *value)
- {
- /* XXX Should we disallow deleting _fields_? */
- if (-1 == PyObject_GenericSetAttr(self, key, value))
- return -1;
-
- if (PyString_Check(key) &&
- 0 == strcmp(PyString_AS_STRING(key), "_fields_"))
- return StructUnionType_update_stgdict(self, value, 0);
- return 0;
- }
- PyTypeObject StructType_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "_ctypes.StructType", /* tp_name */
- 0, /* tp_basicsize */
- 0, /* tp_itemsize */
- 0, /* tp_dealloc */
- 0, /* tp_print */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_compare */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- &CDataType_as_sequence, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- StructType_setattro, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /* tp_flags */
- "metatype for the CData Objects", /* tp_doc */
- (traverseproc)CDataType_traverse, /* tp_traverse */
- (inquiry)CDataType_clear, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- CDataType_methods, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- 0, /* tp_init */
- 0, /* tp_alloc */
- StructType_new, /* tp_new */
- 0, /* tp_free */
- };
- static PyTypeObject UnionType_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "_ctypes.UnionType", /* tp_name */
- 0, /* tp_basicsize */
- 0, /* tp_itemsize */
- 0, /* tp_dealloc */
- 0, /* tp_print */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_compare */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- &CDataType_as_sequence, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- UnionType_setattro, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /* tp_flags */
- "metatype for the CData Objects", /* tp_doc */
- (traverseproc)CDataType_traverse, /* tp_traverse */
- (inquiry)CDataType_clear, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- CDataType_methods, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- 0, /* tp_init */
- 0, /* tp_alloc */
- UnionType_new, /* tp_new */
- 0, /* tp_free */
- };
- /******************************************************************/
- /*
- The PointerType_Type metaclass must ensure that the subclass of Pointer can be
- created. It must check for a _type_ attribute in the class. Since are no
- runtime created properties, a CField is probably *not* needed ?
- class IntPointer(Pointer):
- _type_ = "i"
- The Pointer_Type provides the functionality: a contents method/property, a
- size property/method, and the sequence protocol.
- */
- static int
- PointerType_SetProto(StgDictObject *stgdict, PyObject *proto)
- {
- if (!proto || !PyType_Check(proto)) {
- PyErr_SetString(PyExc_TypeError,
- "_type_ must be a type");
- return -1;
- }
- if (!PyType_stgdict(proto)) {
- PyErr_SetString(PyExc_TypeError,
- "_type_ must have storage info");
- return -1;
- }
- Py_INCREF(proto);
- Py_XDECREF(stgdict->proto);
- stgdict->proto = proto;
- return 0;
- }
- static PyCArgObject *
- PointerType_paramfunc(CDataObject *self)
- {
- PyCArgObject *parg;
- parg = new_CArgObject();
- if (parg == NULL)
- return NULL;
- parg->tag = 'P';
- parg->pffi_type = &ffi_type_pointer;
- Py_INCREF(self);
- parg->obj = (PyObject *)self;
- parg->value.p = *(void **)self->b_ptr;
- return parg;
- }
- static PyObject *
- PointerType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
- {
- PyTypeObject *result;
- StgDictObject *stgdict;
- PyObject *proto;
- PyObject *typedict;
- typedict = PyTuple_GetItem(args, 2);
- if (!typedict)
- return NULL;
- /*
- stgdict items size, align, length contain info about pointers itself,
- stgdict->proto has info about the pointed to type!
- */
- stgdict = (StgDictObject *)PyObject_CallObject(
- (PyObject *)&StgDict_Type, NULL);
- if (!stgdict)
- return NULL;
- stgdict->size = sizeof(void *);
- stgdict->align = getentry("P")->pffi_type->alignment;
- stgdict->length = 1;
- stgdict->ffi_type_pointer = ffi_type_pointer;
- stgdict->paramfunc = PointerType_paramfunc;
- stgdict->flags |= TYPEFLAG_ISPOINTER;
- proto = PyDict_GetItemString(typedict, "_type_"); /* Borrowed ref */
- if (proto && -1 == PointerType_SetProto(stgdict, proto)) {
- Py_DECREF((PyObject *)stgdict);
- return NULL;
- }
- if (proto) {
- StgDictObject *itemdict = PyType_stgdict(proto);
- assert(itemdict);
- /* If itemdict->format is NULL, then this is a pointer to an
- incomplete type. We create a generic format string
- 'pointer to bytes' in this case. XXX Better would be to
- fix the format string later...
- */
- stgdict->format = alloc_format_string("&",
- itemdict->format ? itemdict->format : "B");
- if (stgdict->format == NULL) {
- Py_DECREF((PyObject *)stgdict);
- return NULL;
- }
- }
- /* create the new instance (which is a class,
- since we are a metatype!) */
- result = (PyTypeObject *)PyType_Type.tp_new(type, args, kwds);
- if (result == NULL) {
- Py_DECREF((PyObject *)stgdict);
- return NULL;
- }
- /* replace the class dict by our updated spam dict */
- if (-1 == PyDict_Update((PyObject *)stgdict, result->tp_dict)) {
- Py_DECREF(result);
- Py_DECREF((PyObject *)stgdict);
- return NULL;
- }
- Py_DECREF(result->tp_dict);
- result->tp_dict = (PyObject *)stgdict;
- return (PyObject *)result;
- }
- static PyObject *
- PointerType_set_type(PyTypeObject *self, PyObject *type)
- {
- StgDictObject *dict;
- dict = PyType_stgdict((PyObject *)self);
- assert(dict);
- if (-1 == PointerType_SetProto(dict, type))
- return NULL;
- if (-1 == PyDict_SetItemString((PyObject *)dict, "_type_", type))
- return NULL;
- Py_INCREF(Py_None);
- return Py_None;
- }
- staticforward PyObject *_byref(PyObject *);
- static PyObject *
- PointerType_from_param(PyObject *type, PyObject *value)
- {
- StgDictObject *typedict;
- if (value == Py_None) {
- /* ConvParam will convert to a NULL pointer later */
- Py_INCREF(value);
- return value;
- }
- typedict = PyType_stgdict(type);
- assert(typedict); /* Cannot be NULL for pointer types */
- /* If we expect POINTER(<type>), but receive a <type> instance, accept
- it by calling byref(<type>).
- */
- switch (PyObject_IsInstance(value, typedict->proto)) {
- case 1:
- Py_INCREF(value); /* _byref steals a refcount */
- return _byref(value);
- case -1:
- PyErr_Clear();
- break;
- default:
- break;
- }
- if (PointerObject_Check(value) || ArrayObject_Check(value)) {
- /* Array instances are also pointers when
- the item types are the same.
- */
- StgDictObject *v = PyObject_stgdict(value);
- assert(v); /* Cannot be NULL for pointer or array objects */
- if (PyObject_IsSubclass(v->proto, typedict->proto)) {
- Py_INCREF(value);
- return value;
- }
- }
- return CDataType_from_param(type, value);
- }
- static PyMethodDef PointerType_methods[] = {
- { "from_address", CDataType_from_address, METH_O, from_address_doc },
- { "from_buffer", CDataType_from_buffer, METH_VARARGS, from_buffer_doc, },
- { "from_buffer_copy", CDataType_from_buffer_copy, METH_VARARGS, from_buffer_copy_doc, },
- { "in_dll", CDataType_in_dll, METH_VARARGS, in_dll_doc},
- { "from_param", (PyCFunction)PointerType_from_param, METH_O, from_param_doc},
- { "set_type", (PyCFunction)PointerType_set_type, METH_O },
- { NULL, NULL },
- };
- PyTypeObject PointerType_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "_ctypes.PointerType", /* tp_name */
- 0, /* tp_basicsize */
- 0, /* tp_itemsize */
- 0, /* tp_dealloc */
- 0, /* tp_print */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_compare */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- &CDataType_as_sequence, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /* tp_flags */
- "metatype for the Pointer Objects", /* tp_doc */
- (traverseproc)CDataType_traverse, /* tp_traverse */
- (inquiry)CDataType_clear, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- PointerType_methods, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- 0, /* tp_init */
- 0, /* tp_alloc */
- PointerType_new, /* tp_new */
- 0, /* tp_free */
- };
- /******************************************************************/
- /*
- ArrayType_Type
- */
- /*
- ArrayType_new ensures that the new Array subclass created has a _length_
- attribute, and a _type_ attribute.
- */
- static int
- CharArray_set_raw(CDataObject *self, PyObject *value)
- {
- char *ptr;
- Py_ssize_t size;
- if (PyBuffer_Check(value)) {
- size = Py_TYPE(value)->tp_as_buffer->bf_getreadbuffer(value, 0, (void *)&ptr);
- if (size < 0)
- return -1;
- } else if (-1 == PyString_AsStringAndSize(value, &ptr, &size)) {
- return -1;
- }
- if (size > self->b_size) {
- PyErr_SetString(PyExc_ValueError,
- "string too long");
- return -1;
- }
- memcpy(self->b_ptr, ptr, size);
- return 0;
- }
- static PyObject *
- CharArray_get_raw(CDataObject *self)
- {
- return PyString_FromStringAndSize(self->b_ptr, self->b_size);
- }
- static PyObject *
- CharArray_get_value(CDataObject *self)
- {
- int i;
- char *ptr = self->b_ptr;
- for (i = 0; i < self->b_size; ++i)
- if (*ptr++ == '\0')
- break;
- return PyString_FromStringAndSize(self->b_ptr, i);
- }
- static int
- CharArray_set_value(CDataObject *self, PyObject *value)
- {
- char *ptr;
- Py_ssize_t size;
- if (value == NULL) {
- PyErr_SetString(PyExc_TypeError,
- "can't delete attribute");
- return -1;
- }
- if (PyUnicode_Check(value)) {
- value = PyUnicode_AsEncodedString(value,
- conversion_mode_encoding,
- conversion_mode_errors);
- if (!value)
- return -1;
- } else if (!PyString_Check(value)) {
- PyErr_Format(PyExc_TypeError,
- "string expected instead of %s instance",
- Py_TYPE(value)->tp_name);
- return -1;
- } else
- Py_INCREF(value);
- size = PyString_GET_SIZE(value);
- if (size > self->b_size) {
- PyErr_SetString(PyExc_ValueError,
- "string too long");
- Py_DECREF(value);
- return -1;
- }
- ptr = PyString_AS_STRING(value);
- memcpy(self->b_ptr, ptr, size);
- if (size < self->b_size)
- self->b_ptr[size] = '\0';
- Py_DECREF(value);
- return 0;
- }
- static PyGetSetDef CharArray_getsets[] = {
- { "raw", (getter)CharArray_get_raw, (setter)CharArray_set_raw,
- "value", NULL },
- { "value", (getter)CharArray_get_value, (setter)CharArray_set_value,
- "string value"},
- { NULL, NULL }
- };
- #ifdef CTYPES_UNICODE
- static PyObject *
- WCharArray_get_value(CDataObject *self)
- {
- unsigned int i;
- wchar_t *ptr = (wchar_t *)self->b_ptr;
- for (i = 0; i < self->b_size/sizeof(wchar_t); ++i)
- if (*ptr++ == (wchar_t)0)
- break;
- return PyUnicode_FromWideChar((wchar_t *)self->b_ptr, i);
- }
- static int
- WCharArray_set_value(CDataObject *self, PyObject *value)
- {
- Py_ssize_t result = 0;
- if (value == NULL) {
- PyErr_SetString(PyExc_TypeError,
- "can't delete attribute");
- return -1;
- }
- if (PyString_Check(value)) {
- value = PyUnicode_FromEncodedObject(value,
- conversion_mode_encoding,
- conversion_mode_errors);
- if (!value)
- return -1;
- } else if (!PyUnicode_Check(value)) {
- PyErr_Format(PyExc_TypeError,
- "unicode string expected instead of %s instance",
- Py_TYPE(value)->tp_name);
- return -1;
- } else
- Py_INCREF(value);
- if ((unsigned)PyUnicode_GET_SIZE(value) > self->b_size/sizeof(wchar_t)) {
- PyErr_SetString(PyExc_ValueError,
- "string too long");
- result = -1;
- goto done;
- }
- result = PyUnicode_AsWideChar((PyUnicodeObject *)value,
- (wchar_t *)self->b_ptr,
- self->b_size/sizeof(wchar_t));
- if (result >= 0 && (size_t)result < self->b_size/sizeof(wchar_t))
- ((wchar_t *)self->b_ptr)[result] = (wchar_t)0;
- done:
- Py_DECREF(value);
- return result >= 0 ? 0 : -1;
- }
- static PyGetSetDef WCharArray_getsets[] = {
- { "value", (getter)WCharArray_get_value, (setter)WCharArray_set_value,
- "string value"},
- { NULL, NULL }
- };
- #endif
- /*
- The next three functions copied from Python's typeobject.c.
- They are used to attach methods, members, or getsets to a type *after* it
- has been created: Arrays of characters have additional getsets to treat them
- as strings.
- */
- /*
- static int
- add_methods(PyTypeObject *type, PyMethodDef *meth)
- {
- PyObject *dict = type->tp_dict;
- for (; meth->ml_name != NULL; meth++) {
- PyObject *descr;
- descr = PyDescr_NewMethod(type, meth);
- if (descr == NULL)
- return -1;
- if (PyDict_SetItemString(dict,meth->ml_name, descr) < 0)
- return -1;
- Py_DECREF(descr);
- }
- return 0;
- }
- static int
- add_members(PyTypeObject *type, PyMemberDef *memb)
- {
- PyObject *dict = type->tp_dict;
- for (; memb->name != NULL; memb++) {
- PyObject *descr;
- descr = PyDescr_NewMember(type, memb);
- if (descr == NULL)
- return -1;
- if (PyDict_SetItemString(dict, memb->name, descr) < 0)
- return -1;
- Py_DECREF(descr);
- }
- return 0;
- }
- */
- static int
- add_getset(PyTypeObject *type, PyGetSetDef *gsp)
- {
- PyObject *dict = type->tp_dict;
- for (; gsp->name != NULL; gsp++) {
- PyObject *descr;
- descr = PyDescr_NewGetSet(type, gsp);
- if (descr == NULL)
- return -1;
- if (PyDict_SetItemString(dict, gsp->name, descr) < 0)
- return -1;
- Py_DECREF(descr);
- }
- return 0;
- }
- static PyCArgObject *
- ArrayType_paramfunc(CDataObject *self)
- {
- PyCArgObject *p = new_CArgObject();
- if (p == NULL)
- return NULL;
- p->tag = 'P';
- p->pffi_type = &ffi_type_pointer;
- p->value.p = (char *)self->b_ptr;
- Py_INCREF(self);
- p->obj = (PyObject *)self;
- return p;
- }
- static PyObject *
- ArrayType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
- {
- PyTypeObject *result;
- StgDictObject *stgdict;
- StgDictObject *itemdict;
- PyObject *proto;
- PyObject *typedict;
- long length;
- Py_ssize_t itemsize, itemalign;
- char buf[32];
- typedict = PyTuple_GetItem(args, 2);
- if (!typedict)
- return NULL;
- proto = PyDict_GetItemString(typedict, "_length_"); /* Borrowed ref */
- if (!proto || !PyInt_Check(proto)) {
- PyErr_SetString(PyExc_AttributeError,
- "class must define a '_length_' attribute, "
- "which must be a positive integer");
- return NULL;
- }
- length = PyInt_AS_LONG(proto);
- proto = PyDict_GetItemString(typedict, "_type_"); /* Borrowed ref */
- if (!proto) {
- PyErr_SetString(PyExc_AttributeError,
- "class must define a '_type_' attribute");
- return NULL;
- }
- stgdict = (StgDictObject *)PyObject_CallObject(
- (PyObject *)&StgDict_Type, NULL);
- if (!stgdict)
- return NULL;
- itemdict = PyType_stgdict(proto);
- if (!itemdict) {
- PyErr_SetString(PyExc_TypeError,
- "_type_ must have storage info");
- Py_DECREF((PyObject *)stgdict);
- return NULL;
- }
- assert(itemdict->format);
- if (itemdict->format[0] == '(') {
- sprintf(buf, "(%ld,", length);
- stgdict->format = alloc_format_string(buf, itemdict->format+1);
- } else {
- sprintf(buf, "(%ld)", length);
- stgdict->format = alloc_format_string(buf, itemdict->format);
- }
- if (stgdict->format == NULL) {
- Py_DECREF((PyObject *)stgdict);
- return NULL;
- }
- stgdict->ndim = itemdict->ndim + 1;
- stgdict->shape = PyMem_Malloc(sizeof(Py_ssize_t *) * stgdict->ndim);
- if (stgdict->shape == NULL) {
- Py_DECREF((PyObject *)stgdict);
- return NULL;
- }
- stgdict->shape[0] = length;
- memmove(&stgdict->shape[1], itemdict->shape,
- sizeof(Py_ssize_t) * (stgdict->ndim - 1));
- itemsize = itemdict->size;
- if (length * itemsize < 0) {
- PyErr_SetString(PyExc_OverflowError,
- "array too large");
- return NULL;
- }
- itemalign = itemdict->align;
- if (itemdict->flags & (TYPEFLAG_ISPOINTER | TYPEFLAG_HASPOINTER))
- stgdict->flags |= TYPEFLAG_HASPOINTER;
- stgdict->size = itemsize * length;
- stgdict->align = itemalign;
- stgdict->length = length;
- Py_INCREF(proto);
- stgdict->proto = proto;
- stgdict->paramfunc = &ArrayType_paramfunc;
- /* Arrays are passed as pointers to function calls. */
- stgdict->ffi_type_pointer = ffi_type_pointer;
- /* create the new instance (which is a class,
- since we are a metatype!) */
- result = (PyTypeObject *)PyType_Type.tp_new(type, args, kwds);
- if (result == NULL)
- return NULL;
- /* replace the class dict by our updated spam dict */
- if (-1 == PyDict_Update((PyObject *)stgdict, result->tp_dict)) {
- Py_DECREF(result);
- Py_DECREF((PyObject *)stgdict);
- return NULL;
- }
- Py_DECREF(result->tp_dict);
- result->tp_dict = (PyObject *)stgdict;
- /* Special case for character arrays.
- A permanent annoyance: char arrays are also strings!
- */
- if (itemdict->getfunc == getentry("c")->getfunc) {
- if (-1 == add_getset(result, CharArray_getsets))
- return NULL;
- #ifdef CTYPES_UNICODE
- } else if (itemdict->getfunc == getentry("u")->getfunc) {
- if (-1 == add_getset(result, WCharArray_getsets))
- return NULL;
- #endif
- }
- return (PyObject *)result;
- }
- PyTypeObject ArrayType_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "_ctypes.ArrayType", /* tp_name */
- 0, /* tp_basicsize */
- 0, /* tp_itemsize */
- 0, /* tp_dealloc */
- 0, /* tp_print */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_compare */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- &CDataType_as_sequence, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
- "metatype for the Array Objects", /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- CDataType_methods, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- 0, /* tp_init */
- 0, /* tp_alloc */
- ArrayType_new, /* tp_new */
- 0, /* tp_free */
- };
- /******************************************************************/
- /*
- SimpleType_Type
- */
- /*
- SimpleType_new ensures that the new Simple_Type subclass created has a valid
- _type_ attribute.
- */
- static char *SIMPLE_TYPE_CHARS = "cbBhHiIlLdfuzZqQPXOv?g";
- static PyObject *
- c_wchar_p_from_param(PyObject *type, PyObject *value)
- {
- PyObject *as_parameter;
- #if (PYTHON_API_VERSION < 1012)
- # error not supported
- #endif
- if (value == Py_None) {
- Py_INCREF(Py_None);
- return Py_None;
- }
- if (PyUnicode_Check(value) || PyString_Check(value)) {
- PyCArgObject *parg;
- struct fielddesc *fd = getentry("Z");
- parg = new_CArgObject();
- if (parg == NULL)
- return NULL;
- parg->pffi_type = &ffi_type_pointer;
- parg->tag = 'Z';
- parg->obj = fd->setfunc(&parg->value, value, 0);
- if (parg->obj == NULL) {
- Py_DECREF(parg);
- return NULL;
- }
- return (PyObject *)parg;
- }
- if (PyObject_IsInstance(value, type)) {
- Py_INCREF(value);
- return value;
- }
- if (ArrayObject_Check(value) || PointerObject_Check(value)) {
- /* c_wchar array instance or pointer(c_wchar(...)) */
- StgDictObject *dt = PyObject_stgdict(value);
- StgDictObject *dict;
- assert(dt); /* Cannot be NULL for pointer or array objects */
- dict = dt && dt->proto ? PyType_stgdict(dt->proto) : NULL;
- if (dict && (dict->setfunc == getentry("u")->setfunc)) {
- Py_INCREF(value);
- return value;
- }
- }
- if (PyCArg_CheckExact(value)) {
- /* byref(c_char(...)) */
- PyCArgObject *a = (PyCArgObject *)value;
- StgDictObject *dict = PyObject_stgdict(a->obj);
- if (dict && (dict->setfunc == getentry("u")->setfunc)) {
- Py_INCREF(value);
- return value;
- }
- }
- as_parameter = PyObject_GetAttrString(value, "_as_parameter_");
- if (as_parameter) {
- value = c_wchar_p_from_param(type, as_parameter);
- Py_DECREF(as_parameter);
- return value;
- }
- /* XXX better message */
- PyErr_SetString(PyExc_TypeError,
- "wrong type");
- return NULL;
- }
- static PyObject *
- c_char_p_from_param(PyObject *type, PyObject *value)
- {
- PyObject *as_parameter;
- #if (PYTHON_API_VERSION < 1012)
- # error not supported
- #endif
- if (value == Py_None) {
- Py_INCREF(Py_None);
- return Py_None;
- }
- if (PyString_Check(value) || PyUnicode_Check(value)) {
- PyCArgObject *parg;
- struct fielddesc *fd = getentry("z");
- parg = new_CArgObject();
- if (parg == NULL)
- return NULL;
- parg->pffi_type = &ffi_type_pointer;
- parg->tag = 'z';
- parg->obj = fd->setfunc(&parg->value, value, 0);
- if (parg->obj == NULL) {
- Py_DECREF(parg);
- return NULL;
- }
- return (PyObject *)parg;
- }
- if (PyObject_IsInstance(value, type)) {
- Py_INCREF(value);
- return value;
- }
- if (ArrayObject_Check(value) || PointerObject_Check(value)) {
- /* c_char array instance or pointer(c_char(...)) */
- StgDictObject *dt = PyObject_stgdict(value);
- StgDictObject *dict;
- assert(dt); /* Cannot be NULL for pointer or array objects */
- dict = dt && dt->proto ? PyType_stgdict(dt->proto) : NULL;
- if (dict && (dict->setfunc == getentry("c")->setfunc)) {
- Py_INCREF(value);
- return value;
- }
- }
- if (PyCArg_CheckExact(value)) {
- /* byref(c_char(...)) */
- PyCArgObject *a = (PyCArgObject *)value;
- StgDictObject *dict = PyObject_stgdict(a->obj);
- if (dict && (dict->setfunc == getentry("c")->setfunc)) {
- Py_INCREF(value);
- return value;
- }
- }
- as_parameter = PyObject_GetAttrString(value, "_as_parameter_");
- if (as_parameter) {
- value = c_char_p_from_param(type, as_parameter);
- Py_DECREF(as_parameter);
- return value;
- }
- /* XXX better message */
- PyErr_SetString(PyExc_TypeError,
- "wrong type");
- return NULL;
- }
- static PyObject *
- c_void_p_from_param(PyObject *type, PyObject *value)
- {
- StgDictObject *stgd;
- PyObject *as_parameter;
- #if (PYTHON_API_VERSION < 1012)
- # error not supported
- #endif
- /* None */
- if (value == Py_None) {
- Py_INCREF(Py_None);
- return Py_None;
- }
- /* Should probably allow buffer interface as well */
- /* int, long */
- if (PyInt_Check(value) || PyLong_Check(value)) {
- PyCArgObject *parg;
- struct fielddesc *fd = getentry("P");
- parg = new_CArgObject();
- if (parg == NULL)
- return NULL;
- parg->pffi_type = &ffi_type_pointer;
- parg->tag = 'P';
- parg->obj = fd->setfunc(&parg->value, value, 0);
- if (parg->obj == NULL) {
- Py_DECREF(parg);
- return NULL;
- }
- return (PyObject *)parg;
- }
- /* string */
- if (PyString_Check(value)) {
- PyCArgObject *parg;
- struct fielddesc *fd = getentry("z");
- parg = new_CArgObject();
- if (parg == NULL)
- return NULL;
- parg->pffi_type = &ffi_type_pointer;
- parg->tag = 'z';
- parg->obj = fd->setfunc(&parg->value, value, 0);
- if (parg->obj == NULL) {
- Py_DECREF(parg);
- return NULL;
- }
- return (PyObject *)parg;
- }
- /* unicode */
- if (PyUnicode_Check(value)) {
- PyCArgObject *parg;
- struct fielddesc *fd = getentry("Z");
- parg = new_CArgObject();
- if (parg == NULL)
- return NULL;
- parg->pffi_type = &ffi_type_pointer;
- parg->tag = 'Z';
- parg->obj = fd->setfunc(&parg->value, value, 0);
- if (parg->obj == NULL) {
- Py_DECREF(parg);
- return NULL;
- }
- return (PyObject *)parg;
- }
- /* c_void_p instance (or subclass) */
- if (PyObject_IsInstance(value, type)) {
- /* c_void_p instances */
- Py_INCREF(value);
- return value;
- }
- /* ctypes array or pointer instance */
- if (ArrayObject_Check(value) || PointerObject_Check(value)) {
- /* Any array or pointer is accepted */
- Py_INCREF(value);
- return value;
- }
- /* byref(...) */
- if (PyCArg_CheckExact(value)) {
- /* byref(c_xxx()) */
- PyCArgObject *a = (PyCArgObject *)value;
- if (a->tag == 'P') {
- Py_INCREF(value);
- return value;
- }
- }
- /* function pointer */
- if (CFuncPtrObject_Check(value)) {
- PyCArgObject *parg;
- CFuncPtrObject *func;
- func = (CFuncPtrObject *)value;
- parg = new_CArgObject();
- if (parg == NULL)
- return NULL;
- parg->pffi_type = &ffi_type_pointer;
- parg->tag = 'P';
- Py_INCREF(value);
- parg->value.p = *(void **)func->b_ptr;
- parg->obj = value;
- return (PyObject *)parg;
- }
- /* c_char_p, c_wchar_p */
- stgd = PyObject_stgdict(value);
- if (stgd && CDataObject_Check(value) && stgd->proto && PyString_Check(stgd->proto)) {
- PyCArgObject *parg;
- switch (PyString_AS_STRING(stgd->proto)[0]) {
- case 'z': /* c_char_p */
- case 'Z': /* c_wchar_p */
- parg = new_CArgObject();
- if (parg == NULL)
- return NULL;
- parg->pffi_type = &ffi_type_pointer;
- parg->tag = 'Z';
- Py_INCREF(value);
- parg->obj = value;
- /* Remember: b_ptr points to where the pointer is stored! */
- parg->value.p = *(void **)(((CDataObject *)value)->b_ptr);
- return (PyObject *)parg;
- }
- }
- as_parameter = PyObject_GetAttrString(value, "_as_parameter_");
- if (as_parameter) {
- value = c_void_p_from_param(type, as_parameter);
- Py_DECREF(as_parameter);
- return value;
- }
- /* XXX better message */
- PyErr_SetString(PyExc_TypeError,
- "wrong type");
- return NULL;
- }
- #if (PYTHON_API_VERSION >= 1012)
- static PyMethodDef c_void_p_method = { "from_param", c_void_p_from_param, METH_O };
- static PyMethodDef c_char_p_method = { "from_param", c_char_p_from_param, METH_O };
- static PyMethodDef c_wchar_p_method = { "from_param", c_wchar_p_from_param, METH_O };
- #else
- #error
- static PyMethodDef c_void_p_method = { "from_param", c_void_p_from_param, METH_VARARGS };
- static PyMethodDef c_char_p_method = { "from_param", c_char_p_from_param, METH_VARARGS };
- static PyMethodDef c_wchar_p_method = { "from_param", c_wchar_p_from_param, METH_VARARGS };
- #endif
- static PyObject *CreateSwappedType(PyTypeObject *type, PyObject *args, PyObject *kwds,
- PyObject *proto, struct fielddesc *fmt)
- {
- PyTypeObject *result;
- StgDictObject *stgdict;
- PyObject *name = PyTuple_GET_ITEM(args, 0);
- PyObject *swapped_args;
- static PyObject *suffix;
- Py_ssize_t i;
- swapped_args = PyTuple_New(PyTuple_GET_SIZE(args));
- if (!swapped_args)
- return NULL;
- if (suffix == NULL)
- #ifdef WORDS_BIGENDIAN
- suffix = PyString_InternFromString("_le");
- #else
- suffix = PyString_InternFromString("_be");
- #endif
- Py_INCREF(name);
- PyString_Concat(&name, suffix);
- if (name == NULL)
- return NULL;
- PyTuple_SET_ITEM(swapped_args, 0, name);
- for (i=1; i<PyTuple_GET_SIZE(args); ++i) {
- PyObject *v = PyTuple_GET_ITEM(args, i);
- Py_INCREF(v);
- PyTuple_SET_ITEM(swapped_args, i, v);
- }
- /* create the new instance (which is a class,
- since we are a metatype!) */
- result = (PyTypeObject *)PyType_Type.tp_new(type, swapped_args, kwds);
- Py_DECREF(swapped_args);
- if (result == NULL)
- return NULL;
- stgdict = (StgDictObject *)PyObject_CallObject(
- (PyObject *)&StgDict_Type, NULL);
- if (!stgdict) /* XXX leaks result! */
- return NULL;
- stgdict->ffi_type_pointer = *fmt->pffi_type;
- stgdict->align = fmt->pffi_type->alignment;
- stgdict->length = 0;
- stgdict->size = fmt->pffi_type->size;
- stgdict->setfunc = fmt->setfunc_swapped;
- stgdict->getfunc = fmt->getfunc_swapped;
- Py_INCREF(proto);
- stgdict->proto = proto;
- /* replace the class dict by our updated spam dict */
- if (-1 == PyDict_Update((PyObject *)stgdict, result->tp_dict)) {
- Py_DECREF(result);
- Py_DECREF((PyObject *)stgdict);
- return NULL;
- }
- Py_DECREF(result->tp_dict);
- result->tp_dict = (PyObject *)stgdict;
- return (PyObject *)result;
- }
- static PyCArgObject *
- SimpleType_paramfunc(CDataObject *self)
- {
- StgDictObject *dict;
- char *fmt;
- PyCArgObject *parg;
- struct fielddesc *fd;
-
- dict = PyObject_stgdict((PyObject *)self);
- assert(dict); /* Cannot be NULL for CDataObject instances */
- fmt = PyString_AsString(dict->proto);
- assert(fmt);
- fd = getentry(fmt);
- assert(fd);
-
- parg = new_CArgObject();
- if (parg == NULL)
- return NULL;
-
- parg->tag = fmt[0];
- parg->pffi_type = fd->pffi_type;
- Py_INCREF(self);
- parg->obj = (PyObject *)self;
- memcpy(&parg->value, self->b_ptr, self->b_size);
- return parg;
- }
- static PyObject *
- SimpleType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
- {
- PyTypeObject *result;
- StgDictObject *stgdict;
- PyObject *proto;
- const char *proto_str;
- Py_ssize_t proto_len;
- PyMethodDef *ml;
- struct fielddesc *fmt;
- /* create the new instance (which is a class,
- since we are a metatype!) */
- result = (PyTypeObject *)PyType_Type.tp_new(type, args, kwds);
- if (result == NULL)
- return NULL;
- proto = PyObject_GetAttrString((PyObject *)result, "_type_"); /* new ref */
- if (!proto) {
- PyErr_SetString(PyExc_AttributeError,
- "class must define a '_type_' attribute");
- error:
- Py_XDECREF(proto);
- Py_XDECREF(result);
- return NULL;
- }
- if (PyString_Check(proto)) {
- proto_str = PyString_AS_STRING(proto);
- proto_len = PyString_GET_SIZE(proto);
- } else {
- PyErr_SetString(PyExc_TypeError,
- "class must define a '_type_' string attribute");
- goto error;
- }
- if (proto_len != 1) {
- PyErr_SetString(PyExc_ValueError,
- "class must define a '_type_' attribute "
- "which must be a string of length 1");
- goto error;
- }
- if (!strchr(SIMPLE_TYPE_CHARS, *proto_str)) {
- PyErr_Format(PyExc_AttributeError,
- "class must define a '_type_' attribute which must be\n"
- "a single character string containing one of '%s'.",
- SIMPLE_TYPE_CHARS);
- goto error;
- }
- fmt = getentry(PyString_AS_STRING(proto));
- if (fmt == NULL) {
- Py_DECREF(result);
- PyErr_Format(PyExc_ValueError,
- "_type_ '%s' not supported",
- PyString_AS_STRING(proto));
- return NULL;
- }
- stgdict = (StgDictObject *)PyObject_CallObject(
- (PyObject *)&StgDict_Type, NULL);
- if (!stgdict)
- return NULL;
- stgdict->ffi_type_pointer = *fmt->pffi_type;
- stgdict->align = fmt->pffi_type->alignment;
- stgdict->length = 0;
- stgdict->size = fmt->pffi_type->size;
- stgdict->setfunc = fmt->setfunc;
- stgdict->getfunc = fmt->getfunc;
- #ifdef WORDS_BIGENDIAN
- stgdict->format = alloc_format_string(">", proto_str);
- #else
- stgdict->format = alloc_format_string("<", proto_str);
- #endif
- if (stgdict->format == NULL) {
- Py_DECREF(result);
- Py_DECREF((PyObject *)stgdict);
- return NULL;
- }
- stgdict->paramfunc = SimpleType_paramfunc;
- /*
- if (result->tp_base != &Simple_Type) {
- stgdict->setfunc = NULL;
- stgdict->getfunc = NULL;
- }
- */
- /* This consumes the refcount on proto which we have */
- stgdict->proto = proto;
- /* replace the class dict by our updated spam dict */
- if (-1 == PyDict_Update((PyObject *)stgdict, result->tp_dict)) {
- Py_DECREF(result);
- Py_DECREF((PyObject *)stgdict);
- return NULL;
- }
- Py_DECREF(result->tp_dict);
- result->tp_dict = (PyObject *)stgdict;
- /* Install from_param class methods in ctypes base classes.
- Overrides the SimpleType_from_param generic method.
- */
- if (result->tp_base == &Simple_Type) {
- switch (PyString_AS_STRING(proto)[0]) {
- case 'z': /* c_char_p */
- ml = &c_char_p_method;
- stgdict->flags |= TYPEFLAG_ISPOINTER;
- break;
- case 'Z': /* c_wchar_p */
- ml = &c_wchar_p_method;
- stgdict->flags |= TYPEFLAG_ISPOINTER;
- break;
- case 'P': /* c_void_p */
- ml = &c_void_p_method;
- stgdict->flags |= TYPEFLAG_ISPOINTER;
- break;
- case 's':
- case 'X':
- case 'O':
- ml = NULL;
- stgdict->flags |= TYPEFLAG_ISPOINTER;
- break;
- default:
- ml = NULL;
- break;
- }
-
- if (ml) {
- #if (PYTHON_API_VERSION >= 1012)
- PyObject *meth;
- int x;
- meth = PyDescr_NewClassMethod(result, ml);
- if (!me…