#define PY_SSIZE_T_CLEAN #include #include "structmember.h" #ifdef MS_WIN32 #include #include "misc_win32.h" #else #include #include #include #include #include #include #endif /* this block of #ifs should be kept exactly identical between c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py */ #if defined(_MSC_VER) # include /* for alloca() */ # if _MSC_VER < 1600 /* MSVC < 2010 */ typedef __int8 int8_t; typedef __int16 int16_t; typedef __int32 int32_t; typedef __int64 int64_t; typedef unsigned __int8 uint8_t; typedef unsigned __int16 uint16_t; typedef unsigned __int32 uint32_t; typedef unsigned __int64 uint64_t; typedef __int8 int_least8_t; typedef __int16 int_least16_t; typedef __int32 int_least32_t; typedef __int64 int_least64_t; typedef unsigned __int8 uint_least8_t; typedef unsigned __int16 uint_least16_t; typedef unsigned __int32 uint_least32_t; typedef unsigned __int64 uint_least64_t; typedef __int8 int_fast8_t; typedef __int16 int_fast16_t; typedef __int32 int_fast32_t; typedef __int64 int_fast64_t; typedef unsigned __int8 uint_fast8_t; typedef unsigned __int16 uint_fast16_t; typedef unsigned __int32 uint_fast32_t; typedef unsigned __int64 uint_fast64_t; typedef __int64 intmax_t; typedef unsigned __int64 uintmax_t; # else # include # endif # if _MSC_VER < 1800 /* MSVC < 2013 */ typedef unsigned char _Bool; # endif #else # include # if (defined (__SVR4) && defined (__sun)) || defined(_AIX) # include # endif #endif #include "malloc_closure.h" #if PY_MAJOR_VERSION >= 3 # define STR_OR_BYTES "bytes" # define PyText_Type PyUnicode_Type # define PyText_Check PyUnicode_Check # define PyTextAny_Check PyUnicode_Check # define PyText_FromFormat PyUnicode_FromFormat # define PyText_AsUTF8 _PyUnicode_AsString /* PyUnicode_AsUTF8 in Py3.3 */ # define PyText_AS_UTF8 _PyUnicode_AsString # define PyText_GetSize PyUnicode_GetSize # define PyText_FromString PyUnicode_FromString # define PyText_FromStringAndSize PyUnicode_FromStringAndSize # define PyText_InternInPlace PyUnicode_InternInPlace # define PyIntOrLong_Check PyLong_Check #else # define STR_OR_BYTES "str" # define PyText_Type PyString_Type # define PyText_Check PyString_Check # define PyTextAny_Check(op) (PyString_Check(op) || PyUnicode_Check(op)) # define PyText_FromFormat PyString_FromFormat # define PyText_AsUTF8 PyString_AsString # define PyText_AS_UTF8 PyString_AS_STRING # define PyText_GetSize PyString_Size # define PyText_FromString PyString_FromString # define PyText_FromStringAndSize PyString_FromStringAndSize # define PyText_InternInPlace PyString_InternInPlace # define PyIntOrLong_Check(op) (PyInt_Check(op) || PyLong_Check(op)) #endif #if PY_MAJOR_VERSION >= 3 # define PyInt_FromLong PyLong_FromLong # define PyInt_FromSsize_t PyLong_FromSsize_t # define PyInt_AsSsize_t PyLong_AsSsize_t #endif #if PY_MAJOR_VERSION >= 3 /* This is the default on Python3 and constant has been removed. */ # define Py_TPFLAGS_CHECKTYPES 0 #endif #if PY_MAJOR_VERSION < 3 #define PyCapsule_New(pointer, name, destructor) \ (PyCObject_FromVoidPtr(pointer, destructor)) #endif /************************************************************/ /* base type flag: exactly one of the following: */ #define CT_PRIMITIVE_SIGNED 1 /* signed integer */ #define CT_PRIMITIVE_UNSIGNED 2 /* unsigned integer */ #define CT_PRIMITIVE_CHAR 4 /* char, wchar_t */ #define CT_PRIMITIVE_FLOAT 8 /* float, double, long double */ #define CT_POINTER 16 /* pointer, excluding ptr-to-func */ #define CT_ARRAY 32 /* array */ #define CT_STRUCT 64 /* struct */ #define CT_UNION 128 /* union */ #define CT_FUNCTIONPTR 256 /* pointer to function */ #define CT_VOID 512 /* void */ /* other flags that may also be set in addition to the base flag: */ #define CT_CAST_ANYTHING 1024 /* 'char *' and 'void *' only */ #define CT_PRIMITIVE_FITS_LONG 2048 #define CT_IS_OPAQUE 4096 #define CT_IS_ENUM 8192 #define CT_IS_PTR_TO_OWNED 16384 #define CT_CUSTOM_FIELD_POS 32768 #define CT_IS_LONGDOUBLE 65536 #define CT_IS_BOOL 131072 #define CT_IS_FILE 262144 #define CT_IS_VOID_PTR 524288 #define CT_WITH_VAR_ARRAY 1048576 #define CT_PRIMITIVE_ANY (CT_PRIMITIVE_SIGNED | \ CT_PRIMITIVE_UNSIGNED | \ CT_PRIMITIVE_CHAR | \ CT_PRIMITIVE_FLOAT) typedef struct _ctypedescr { PyObject_VAR_HEAD struct _ctypedescr *ct_itemdescr; /* ptrs and arrays: the item type */ PyObject *ct_stuff; /* structs: dict of the fields arrays: ctypedescr of the ptr type function: tuple(abi, ctres, ctargs..) enum: pair {"name":x},{x:"name"} ptrs: lazily, ctypedescr of array */ void *ct_extra; /* structs: first field (not a ref!) function types: cif_description primitives: prebuilt "cif" object */ PyObject *ct_weakreflist; /* weakref support */ Py_ssize_t ct_size; /* size of instances, or -1 if unknown */ Py_ssize_t ct_length; /* length of arrays, or -1 if unknown; or alignment of primitive and struct types; always -1 for pointers */ int ct_flags; /* CT_xxx flags */ int ct_name_position; /* index in ct_name of where to put a var name */ char ct_name[1]; /* string, e.g. "int *" for pointers to ints */ } CTypeDescrObject; typedef struct { PyObject_HEAD CTypeDescrObject *c_type; char *c_data; PyObject *c_weakreflist; } CDataObject; typedef struct cfieldobject_s { PyObject_HEAD CTypeDescrObject *cf_type; Py_ssize_t cf_offset; short cf_bitshift; /* >= 0: bitshift; or BS_REGULAR or BS_EMPTY_ARRAY */ short cf_bitsize; struct cfieldobject_s *cf_next; } CFieldObject; #define BS_REGULAR (-1) /* a regular field, not with bitshift */ #define BS_EMPTY_ARRAY (-2) /* a field which is an array 'type[0]' */ static PyTypeObject CTypeDescr_Type; static PyTypeObject CField_Type; static PyTypeObject CData_Type; static PyTypeObject CDataOwning_Type; static PyTypeObject CDataOwningGC_Type; #define CTypeDescr_Check(ob) (Py_TYPE(ob) == &CTypeDescr_Type) #define CData_Check(ob) (Py_TYPE(ob) == &CData_Type || \ Py_TYPE(ob) == &CDataOwning_Type || \ Py_TYPE(ob) == &CDataOwningGC_Type) #define CDataOwn_Check(ob) (Py_TYPE(ob) == &CDataOwning_Type || \ Py_TYPE(ob) == &CDataOwningGC_Type) typedef union { unsigned char m_char; unsigned short m_short; unsigned int m_int; unsigned long m_long; unsigned long long m_longlong; float m_float; double m_double; long double m_longdouble; } union_alignment; typedef struct { CDataObject head; union_alignment alignment; } CDataObject_casted_primitive; typedef struct { CDataObject head; union_alignment alignment; } CDataObject_own_nolength; typedef struct { CDataObject head; Py_ssize_t length; union_alignment alignment; } CDataObject_own_length; typedef struct { CDataObject head; PyObject *structobj; } CDataObject_own_structptr; typedef struct { ffi_cif cif; /* the following information is used when doing the call: - a buffer of size 'exchange_size' is malloced - the arguments are converted from Python objects to raw data - the i'th raw data is stored at 'buffer + exchange_offset_arg[1+i]' - the call is done - the result is read back from 'buffer + exchange_offset_arg[0]' */ Py_ssize_t exchange_size; Py_ssize_t exchange_offset_arg[1]; } cif_description_t; /* whenever running Python code, the errno is saved in this thread-local variable */ #ifndef MS_WIN32 # ifdef USE__THREAD /* This macro ^^^ is defined by setup.py if it finds that it is syntactically valid to use "__thread" with this C compiler. */ static __thread int cffi_saved_errno = 0; static void save_errno(void) { cffi_saved_errno = errno; } static void restore_errno(void) { errno = cffi_saved_errno; } static void init_errno(void) { } # else # include "misc_thread.h" # endif # define save_errno_only save_errno # define restore_errno_only restore_errno #endif #include "minibuffer.h" #if PY_MAJOR_VERSION >= 3 # include "file_emulator.h" #endif #ifdef HAVE_WCHAR_H # include "wchar_helper.h" #endif /************************************************************/ static CTypeDescrObject * ctypedescr_new(int name_size) { CTypeDescrObject *ct = PyObject_GC_NewVar(CTypeDescrObject, &CTypeDescr_Type, name_size); if (ct == NULL) return NULL; ct->ct_itemdescr = NULL; ct->ct_stuff = NULL; ct->ct_weakreflist = NULL; PyObject_GC_Track(ct); return ct; } static CTypeDescrObject * ctypedescr_new_on_top(CTypeDescrObject *ct_base, const char *extra_text, int extra_position) { int base_name_len = strlen(ct_base->ct_name); int extra_name_len = strlen(extra_text); CTypeDescrObject *ct = ctypedescr_new(base_name_len + extra_name_len + 1); char *p; if (ct == NULL) return NULL; Py_INCREF(ct_base); ct->ct_itemdescr = ct_base; ct->ct_name_position = ct_base->ct_name_position + extra_position; p = ct->ct_name; memcpy(p, ct_base->ct_name, ct_base->ct_name_position); p += ct_base->ct_name_position; memcpy(p, extra_text, extra_name_len); p += extra_name_len; memcpy(p, ct_base->ct_name + ct_base->ct_name_position, base_name_len - ct_base->ct_name_position + 1); return ct; } static PyObject * ctypedescr_repr(CTypeDescrObject *ct) { return PyText_FromFormat("", ct->ct_name); } static void ctypedescr_dealloc(CTypeDescrObject *ct) { PyObject_GC_UnTrack(ct); if (ct->ct_weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *) ct); Py_XDECREF(ct->ct_itemdescr); Py_XDECREF(ct->ct_stuff); if (ct->ct_flags & CT_FUNCTIONPTR) PyObject_Free(ct->ct_extra); Py_TYPE(ct)->tp_free((PyObject *)ct); } static int ctypedescr_traverse(CTypeDescrObject *ct, visitproc visit, void *arg) { Py_VISIT(ct->ct_itemdescr); Py_VISIT(ct->ct_stuff); return 0; } static int ctypedescr_clear(CTypeDescrObject *ct) { Py_CLEAR(ct->ct_itemdescr); Py_CLEAR(ct->ct_stuff); return 0; } static PyObject *nosuchattr(const char *attr) { PyErr_SetString(PyExc_AttributeError, attr); return NULL; } static PyObject *ctypeget_kind(CTypeDescrObject *ct, void *context) { char *result; if (ct->ct_flags & CT_PRIMITIVE_ANY) { if (ct->ct_flags & CT_IS_ENUM) result = "enum"; else result = "primitive"; } else if (ct->ct_flags & CT_POINTER) { result = "pointer"; } else if (ct->ct_flags & CT_ARRAY) { result = "array"; } else if (ct->ct_flags & CT_VOID) { result = "void"; } else if (ct->ct_flags & CT_STRUCT) { result = "struct"; } else if (ct->ct_flags & CT_UNION) { result = "union"; } else if (ct->ct_flags & CT_FUNCTIONPTR) { result = "function"; } else result = "?"; return PyText_FromString(result); } static PyObject *ctypeget_cname(CTypeDescrObject *ct, void *context) { return PyText_FromString(ct->ct_name); } static PyObject *ctypeget_item(CTypeDescrObject *ct, void *context) { if (ct->ct_flags & (CT_POINTER | CT_ARRAY)) { Py_INCREF(ct->ct_itemdescr); return (PyObject *)ct->ct_itemdescr; } return nosuchattr("item"); } static PyObject *ctypeget_length(CTypeDescrObject *ct, void *context) { if (ct->ct_flags & CT_ARRAY) { if (ct->ct_length >= 0) { return PyInt_FromSsize_t(ct->ct_length); } else { Py_INCREF(Py_None); return Py_None; } } return nosuchattr("length"); } static PyObject * get_field_name(CTypeDescrObject *ct, CFieldObject *cf); /* forward */ static PyObject *ctypeget_fields(CTypeDescrObject *ct, void *context) { if (ct->ct_flags & (CT_STRUCT | CT_UNION)) { if (!(ct->ct_flags & CT_IS_OPAQUE)) { CFieldObject *cf; PyObject *res = PyList_New(0); if (res == NULL) return NULL; for (cf = (CFieldObject *)ct->ct_extra; cf != NULL; cf = cf->cf_next) { PyObject *o = PyTuple_Pack(2, get_field_name(ct, cf), (PyObject *)cf); int err = (o != NULL) ? PyList_Append(res, o) : -1; Py_XDECREF(o); if (err < 0) { Py_DECREF(res); return NULL; } } return res; } else { Py_INCREF(Py_None); return Py_None; } } return nosuchattr("fields"); } static PyObject *ctypeget_args(CTypeDescrObject *ct, void *context) { if (ct->ct_flags & CT_FUNCTIONPTR) { PyObject *t = ct->ct_stuff; return PyTuple_GetSlice(t, 2, PyTuple_GET_SIZE(t)); } return nosuchattr("args"); } static PyObject *ctypeget_result(CTypeDescrObject *ct, void *context) { if (ct->ct_flags & CT_FUNCTIONPTR) { PyObject *res = PyTuple_GetItem(ct->ct_stuff, 1); Py_XINCREF(res); return res; } return nosuchattr("result"); } static PyObject *ctypeget_ellipsis(CTypeDescrObject *ct, void *context) { if (ct->ct_flags & CT_FUNCTIONPTR) { PyObject *res = ct->ct_extra ? Py_False : Py_True; Py_INCREF(res); return res; } return nosuchattr("ellipsis"); } static PyObject *ctypeget_abi(CTypeDescrObject *ct, void *context) { if (ct->ct_flags & CT_FUNCTIONPTR) { PyObject *res = PyTuple_GetItem(ct->ct_stuff, 0); Py_XINCREF(res); return res; } return nosuchattr("abi"); } static PyObject *ctypeget_elements(CTypeDescrObject *ct, void *context) { if (ct->ct_flags & CT_IS_ENUM) { PyObject *res = PyTuple_GetItem(ct->ct_stuff, 1); if (res) res = PyDict_Copy(res); return res; } return nosuchattr("elements"); } static PyObject *ctypeget_relements(CTypeDescrObject *ct, void *context) { if (ct->ct_flags & CT_IS_ENUM) { PyObject *res = PyTuple_GetItem(ct->ct_stuff, 0); if (res) res = PyDict_Copy(res); return res; } return nosuchattr("relements"); } static PyGetSetDef ctypedescr_getsets[] = { {"kind", (getter)ctypeget_kind, NULL, "kind"}, {"cname", (getter)ctypeget_cname, NULL, "C name"}, {"item", (getter)ctypeget_item, NULL, "pointer to, or array of"}, {"length", (getter)ctypeget_length, NULL, "array length or None"}, {"fields", (getter)ctypeget_fields, NULL, "struct or union fields"}, {"args", (getter)ctypeget_args, NULL, "function argument types"}, {"result", (getter)ctypeget_result, NULL, "function result type"}, {"ellipsis", (getter)ctypeget_ellipsis, NULL, "function has '...'"}, {"abi", (getter)ctypeget_abi, NULL, "function ABI"}, {"elements", (getter)ctypeget_elements, NULL, "enum elements"}, {"relements", (getter)ctypeget_relements, NULL, "enum elements, reverse"}, {NULL} /* sentinel */ }; static PyObject * ctypedescr_dir(PyObject *ct, PyObject *noarg) { int err; struct PyGetSetDef *gsdef; PyObject *res = PyList_New(0); if (res == NULL) return NULL; for (gsdef = ctypedescr_getsets; gsdef->name; gsdef++) { PyObject *x = PyObject_GetAttrString(ct, gsdef->name); if (x == NULL) { PyErr_Clear(); } else { Py_DECREF(x); x = PyText_FromString(gsdef->name); err = (x != NULL) ? PyList_Append(res, x) : -1; Py_XDECREF(x); if (err < 0) { Py_DECREF(res); return NULL; } } } return res; } static PyMethodDef ctypedescr_methods[] = { {"__dir__", ctypedescr_dir, METH_NOARGS}, {NULL, NULL} /* sentinel */ }; static PyTypeObject CTypeDescr_Type = { PyVarObject_HEAD_INIT(NULL, 0) "_cffi_backend.CTypeDescr", offsetof(CTypeDescrObject, ct_name), sizeof(char), (destructor)ctypedescr_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ (reprfunc)ctypedescr_repr, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ 0, /* tp_doc */ (traverseproc)ctypedescr_traverse, /* tp_traverse */ (inquiry)ctypedescr_clear, /* tp_clear */ 0, /* tp_richcompare */ offsetof(CTypeDescrObject, ct_weakreflist), /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ ctypedescr_methods, /* tp_methods */ 0, /* tp_members */ ctypedescr_getsets, /* tp_getset */ }; /************************************************************/ static PyObject * get_field_name(CTypeDescrObject *ct, CFieldObject *cf) { Py_ssize_t i = 0; PyObject *d_key, *d_value; while (PyDict_Next(ct->ct_stuff, &i, &d_key, &d_value)) { if (d_value == (PyObject *)cf) return d_key; } Py_FatalError("_cffi_backend: get_field_name()"); return NULL; } static void cfield_dealloc(CFieldObject *cf) { Py_DECREF(cf->cf_type); PyObject_Del(cf); } #undef OFF #define OFF(x) offsetof(CFieldObject, x) static PyMemberDef cfield_members[] = { {"type", T_OBJECT, OFF(cf_type), READONLY}, {"offset", T_PYSSIZET, OFF(cf_offset), READONLY}, {"bitshift", T_SHORT, OFF(cf_bitshift), READONLY}, {"bitsize", T_SHORT, OFF(cf_bitsize), READONLY}, {NULL} /* Sentinel */ }; #undef OFF static PyTypeObject CField_Type = { PyVarObject_HEAD_INIT(NULL, 0) "_cffi_backend.CField", sizeof(CFieldObject), 0, (destructor)cfield_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 */ 0, /* tp_call */ 0, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ 0, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ 0, /* tp_methods */ cfield_members, /* tp_members */ }; /************************************************************/ static int CDataObject_Or_PyFloat_Check(PyObject *ob) { return (PyFloat_Check(ob) || (CData_Check(ob) && (((CDataObject *)ob)->c_type->ct_flags & CT_PRIMITIVE_FLOAT))); } static PY_LONG_LONG _my_PyLong_AsLongLong(PyObject *ob) { /* (possibly) convert and cast a Python object to a long long. Like PyLong_AsLongLong(), this version accepts a Python int too, and does convertions from other types of objects. The difference is that this version refuses floats. */ #if PY_MAJOR_VERSION < 3 if (PyInt_Check(ob)) { return PyInt_AS_LONG(ob); } else #endif if (PyLong_Check(ob)) { return PyLong_AsLongLong(ob); } else { PyObject *io; PY_LONG_LONG res; PyNumberMethods *nb = ob->ob_type->tp_as_number; if (CDataObject_Or_PyFloat_Check(ob) || nb == NULL || nb->nb_int == NULL) { PyErr_SetString(PyExc_TypeError, "an integer is required"); return -1; } io = (*nb->nb_int) (ob); if (io == NULL) return -1; if (PyIntOrLong_Check(io)) { res = _my_PyLong_AsLongLong(io); } else { PyErr_SetString(PyExc_TypeError, "integer conversion failed"); res = -1; } Py_DECREF(io); return res; } } static unsigned PY_LONG_LONG _my_PyLong_AsUnsignedLongLong(PyObject *ob, int strict) { /* (possibly) convert and cast a Python object to an unsigned long long. Like PyLong_AsLongLong(), this version accepts a Python int too, and does convertions from other types of objects. If 'strict', complains with OverflowError and refuses floats. If '!strict', rounds floats and masks the result. */ #if PY_MAJOR_VERSION < 3 if (PyInt_Check(ob)) { long value1 = PyInt_AS_LONG(ob); if (strict && value1 < 0) goto negative; return (unsigned PY_LONG_LONG)(PY_LONG_LONG)value1; } else #endif if (PyLong_Check(ob)) { if (strict) { if (_PyLong_Sign(ob) < 0) goto negative; return PyLong_AsUnsignedLongLong(ob); } else { return PyLong_AsUnsignedLongLongMask(ob); } } else { PyObject *io; unsigned PY_LONG_LONG res; PyNumberMethods *nb = ob->ob_type->tp_as_number; if ((strict && CDataObject_Or_PyFloat_Check(ob)) || nb == NULL || nb->nb_int == NULL) { PyErr_SetString(PyExc_TypeError, "an integer is required"); return (unsigned PY_LONG_LONG)-1; } io = (*nb->nb_int) (ob); if (io == NULL) return (unsigned PY_LONG_LONG)-1; if (PyIntOrLong_Check(io)) { res = _my_PyLong_AsUnsignedLongLong(io, strict); } else { PyErr_SetString(PyExc_TypeError, "integer conversion failed"); res = (unsigned PY_LONG_LONG)-1; } Py_DECREF(io); return res; } negative: PyErr_SetString(PyExc_OverflowError, "can't convert negative number to unsigned"); return (unsigned PY_LONG_LONG)-1; } #define _read_raw_data(type) \ do { \ if (size == sizeof(type)) { \ type r; \ memcpy(&r, target, sizeof(type)); \ return r; \ } \ } while(0) static PY_LONG_LONG read_raw_signed_data(char *target, int size) { _read_raw_data(signed char); _read_raw_data(short); _read_raw_data(int); _read_raw_data(long); _read_raw_data(PY_LONG_LONG); Py_FatalError("read_raw_signed_data: bad integer size"); return 0; } static unsigned PY_LONG_LONG read_raw_unsigned_data(char *target, int size) { _read_raw_data(unsigned char); _read_raw_data(unsigned short); _read_raw_data(unsigned int); _read_raw_data(unsigned long); _read_raw_data(unsigned PY_LONG_LONG); Py_FatalError("read_raw_unsigned_data: bad integer size"); return 0; } #define _write_raw_data(type) \ do { \ if (size == sizeof(type)) { \ type r = (type)source; \ memcpy(target, &r, sizeof(type)); \ return; \ } \ } while(0) static void write_raw_integer_data(char *target, unsigned PY_LONG_LONG source, int size) { _write_raw_data(unsigned char); _write_raw_data(unsigned short); _write_raw_data(unsigned int); _write_raw_data(unsigned long); _write_raw_data(unsigned PY_LONG_LONG); Py_FatalError("write_raw_integer_data: bad integer size"); } static double read_raw_float_data(char *target, int size) { _read_raw_data(float); _read_raw_data(double); Py_FatalError("read_raw_float_data: bad float size"); return 0; } static long double read_raw_longdouble_data(char *target) { int size = sizeof(long double); _read_raw_data(long double); Py_FatalError("read_raw_longdouble_data: bad long double size"); return 0; } static void write_raw_float_data(char *target, double source, int size) { _write_raw_data(float); _write_raw_data(double); Py_FatalError("write_raw_float_data: bad float size"); } static void write_raw_longdouble_data(char *target, long double source) { int size = sizeof(long double); _write_raw_data(long double); } static PyObject * new_simple_cdata(char *data, CTypeDescrObject *ct) { CDataObject *cd = PyObject_New(CDataObject, &CData_Type); if (cd == NULL) return NULL; Py_INCREF(ct); cd->c_data = data; cd->c_type = ct; cd->c_weakreflist = NULL; return (PyObject *)cd; } static CDataObject *_new_casted_primitive(CTypeDescrObject *ct); /*forward*/ static PyObject * convert_to_object(char *data, CTypeDescrObject *ct) { if (!(ct->ct_flags & CT_PRIMITIVE_ANY)) { /* non-primitive types (check done just for performance) */ if (ct->ct_flags & (CT_POINTER|CT_FUNCTIONPTR)) { char *ptrdata = *(char **)data; /*READ(data, sizeof(char *))*/ return new_simple_cdata(ptrdata, ct); } else if (ct->ct_flags & CT_IS_OPAQUE) { PyErr_Format(PyExc_TypeError, "cdata '%s' is opaque", ct->ct_name); return NULL; } else if (ct->ct_flags & (CT_STRUCT|CT_UNION)) { return new_simple_cdata(data, ct); } else if (ct->ct_flags & CT_ARRAY) { if (ct->ct_length < 0) { /* we can't return a here, because we don't know the length to give it. As a compromize, returns in this case. */ ct = (CTypeDescrObject *)ct->ct_stuff; } return new_simple_cdata(data, ct); } } else if (ct->ct_flags & CT_PRIMITIVE_SIGNED) { PY_LONG_LONG value; /*READ(data, ct->ct_size)*/ value = read_raw_signed_data(data, ct->ct_size); if (ct->ct_flags & CT_PRIMITIVE_FITS_LONG) return PyInt_FromLong((long)value); else return PyLong_FromLongLong(value); } else if (ct->ct_flags & CT_PRIMITIVE_UNSIGNED) { unsigned PY_LONG_LONG value; /*READ(data, ct->ct_size)*/ value = read_raw_unsigned_data(data, ct->ct_size); if (ct->ct_flags & CT_PRIMITIVE_FITS_LONG) return PyInt_FromLong((long)value); else return PyLong_FromUnsignedLongLong(value); } else if (ct->ct_flags & CT_PRIMITIVE_FLOAT) { /*READ(data, ct->ct_size)*/ if (!(ct->ct_flags & CT_IS_LONGDOUBLE)) { double value = read_raw_float_data(data, ct->ct_size); return PyFloat_FromDouble(value); } else { long double value = read_raw_longdouble_data(data); CDataObject *cd = _new_casted_primitive(ct); if (cd != NULL) write_raw_longdouble_data(cd->c_data, value); return (PyObject *)cd; } } else if (ct->ct_flags & CT_PRIMITIVE_CHAR) { /*READ(data, ct->ct_size)*/ if (ct->ct_size == sizeof(char)) return PyBytes_FromStringAndSize(data, 1); #ifdef HAVE_WCHAR_H else return _my_PyUnicode_FromWideChar((wchar_t *)data, 1); #endif } PyErr_Format(PyExc_SystemError, "convert_to_object: '%s'", ct->ct_name); return NULL; } static PyObject * convert_to_object_bitfield(char *data, CFieldObject *cf) { CTypeDescrObject *ct = cf->cf_type; /*READ(data, ct->ct_size)*/ if (ct->ct_flags & CT_PRIMITIVE_SIGNED) { unsigned PY_LONG_LONG value, valuemask, shiftforsign; PY_LONG_LONG result; value = (unsigned PY_LONG_LONG)read_raw_signed_data(data, ct->ct_size); valuemask = (1ULL << cf->cf_bitsize) - 1ULL; shiftforsign = 1ULL << (cf->cf_bitsize - 1); value = ((value >> cf->cf_bitshift) + shiftforsign) & valuemask; result = ((PY_LONG_LONG)value) - (PY_LONG_LONG)shiftforsign; if (ct->ct_flags & CT_PRIMITIVE_FITS_LONG) return PyInt_FromLong((long)result); else return PyLong_FromLongLong(result); } else { unsigned PY_LONG_LONG value, valuemask; value = read_raw_unsigned_data(data, ct->ct_size); valuemask = (1ULL << cf->cf_bitsize) - 1ULL; value = (value >> cf->cf_bitshift) & valuemask; if (ct->ct_flags & CT_PRIMITIVE_FITS_LONG) return PyInt_FromLong((long)value); else return PyLong_FromUnsignedLongLong(value); } } static int _convert_overflow(PyObject *init, const char *ct_name) { PyObject *s; if (PyErr_Occurred()) /* already an exception pending */ return -1; s = PyObject_Str(init); if (s == NULL) return -1; PyErr_Format(PyExc_OverflowError, "integer %s does not fit '%s'", PyText_AS_UTF8(s), ct_name); Py_DECREF(s); return -1; } static int _convert_to_char(PyObject *init) { if (PyBytes_Check(init) && PyBytes_GET_SIZE(init) == 1) { return (unsigned char)(PyBytes_AS_STRING(init)[0]); } if (CData_Check(init) && (((CDataObject *)init)->c_type->ct_flags & CT_PRIMITIVE_CHAR) && (((CDataObject *)init)->c_type->ct_size == sizeof(char))) { char *data = ((CDataObject *)init)->c_data; /*READ(data, 1)*/ return *(unsigned char *)data; } PyErr_Format(PyExc_TypeError, "initializer for ctype 'char' must be a "STR_OR_BYTES " of length 1, not %.200s", Py_TYPE(init)->tp_name); return -1; } #ifdef HAVE_WCHAR_H static wchar_t _convert_to_wchar_t(PyObject *init) { if (PyUnicode_Check(init)) { wchar_t ordinal; if (_my_PyUnicode_AsSingleWideChar(init, &ordinal) == 0) return ordinal; } if (CData_Check(init) && (((CDataObject *)init)->c_type->ct_flags & CT_PRIMITIVE_CHAR) && (((CDataObject *)init)->c_type->ct_size == sizeof(wchar_t))) { char *data = ((CDataObject *)init)->c_data; /*READ(data, sizeof(wchar_t))*/ return *(wchar_t *)data; } PyErr_Format(PyExc_TypeError, "initializer for ctype 'wchar_t' must be a unicode string " "of length 1, not %.200s", Py_TYPE(init)->tp_name); return (wchar_t)-1; } #endif static int _convert_error(PyObject *init, const char *ct_name, const char *expected) { if (CData_Check(init)) PyErr_Format(PyExc_TypeError, "initializer for ctype '%s' must be a %s, " "not cdata '%s'", ct_name, expected, ((CDataObject *)init)->c_type->ct_name); else PyErr_Format(PyExc_TypeError, "initializer for ctype '%s' must be a %s, " "not %.200s", ct_name, expected, Py_TYPE(init)->tp_name); return -1; } static int /* forward */ convert_from_object(char *data, CTypeDescrObject *ct, PyObject *init); static int /* forward */ convert_from_object_bitfield(char *data, CFieldObject *cf, PyObject *init); static Py_ssize_t get_new_array_length(PyObject **pvalue) { PyObject *value = *pvalue; if (PyList_Check(value) || PyTuple_Check(value)) { return PySequence_Fast_GET_SIZE(value); } else if (PyBytes_Check(value)) { /* from a string, we add the null terminator */ return PyBytes_GET_SIZE(value) + 1; } else if (PyUnicode_Check(value)) { /* from a unicode, we add the null terminator */ return _my_PyUnicode_SizeAsWideChar(value) + 1; } else { Py_ssize_t explicitlength; explicitlength = PyNumber_AsSsize_t(value, PyExc_OverflowError); if (explicitlength < 0) { if (!PyErr_Occurred()) PyErr_SetString(PyExc_ValueError, "negative array length"); return -1; } *pvalue = Py_None; return explicitlength; } } static int convert_field_from_object(char *data, CFieldObject *cf, PyObject *value) { data += cf->cf_offset; if (cf->cf_bitshift >= 0) return convert_from_object_bitfield(data, cf, value); else return convert_from_object(data, cf->cf_type, value); } static int convert_vfield_from_object(char *data, CFieldObject *cf, PyObject *value, Py_ssize_t *optvarsize) { /* a special case for var-sized C99 arrays */ if ((cf->cf_type->ct_flags & CT_ARRAY) && cf->cf_type->ct_size < 0) { Py_ssize_t varsizelength = get_new_array_length(&value); if (varsizelength < 0) return -1; if (optvarsize != NULL) { /* in this mode, the only purpose of this function is to compute the real size of the structure from a var-sized C99 array */ Py_ssize_t size, itemsize; assert(data == NULL); itemsize = cf->cf_type->ct_itemdescr->ct_size; size = cf->cf_offset + itemsize * varsizelength; if (size < 0 || ((size - cf->cf_offset) / itemsize) != varsizelength) { PyErr_SetString(PyExc_OverflowError, "array size would overflow a Py_ssize_t"); return -1; } if (size > *optvarsize) *optvarsize = size; return 0; } /* if 'value' was only an integer, get_new_array_length() returns it and convert 'value' to be None. Detect if this was the case, and if so, stop here, leaving the content uninitialized (it should be zero-initialized from somewhere else). */ if (value == Py_None) return 0; } if (optvarsize == NULL) return convert_field_from_object(data, cf, value); else return 0; } static int convert_array_from_object(char *data, CTypeDescrObject *ct, PyObject *init) { /* used by convert_from_object(), and also to decode lists/tuples/unicodes passed as function arguments. 'ct' is an CT_ARRAY in the first case and a CT_POINTER in the second case. */ const char *expected; CTypeDescrObject *ctitem = ct->ct_itemdescr; if (PyList_Check(init) || PyTuple_Check(init)) { PyObject **items; Py_ssize_t i, n; n = PySequence_Fast_GET_SIZE(init); if (ct->ct_length >= 0 && n > ct->ct_length) { PyErr_Format(PyExc_IndexError, "too many initializers for '%s' (got %zd)", ct->ct_name, n); return -1; } items = PySequence_Fast_ITEMS(init); for (i=0; ict_size; } return 0; } else if ((ctitem->ct_flags & CT_PRIMITIVE_CHAR) || ((ctitem->ct_flags & (CT_PRIMITIVE_SIGNED|CT_PRIMITIVE_UNSIGNED)) && (ctitem->ct_size == sizeof(char)))) { if (ctitem->ct_size == sizeof(char)) { char *srcdata; Py_ssize_t n; if (!PyBytes_Check(init)) { expected = STR_OR_BYTES" or list or tuple"; goto cannot_convert; } n = PyBytes_GET_SIZE(init); if (ct->ct_length >= 0 && n > ct->ct_length) { PyErr_Format(PyExc_IndexError, "initializer "STR_OR_BYTES" is too long for '%s' " "(got %zd characters)", ct->ct_name, n); return -1; } if (n != ct->ct_length) n++; srcdata = PyBytes_AS_STRING(init); memcpy(data, srcdata, n); return 0; } #ifdef HAVE_WCHAR_H else { Py_ssize_t n; if (!PyUnicode_Check(init)) { expected = "unicode or list or tuple"; goto cannot_convert; } n = _my_PyUnicode_SizeAsWideChar(init); if (ct->ct_length >= 0 && n > ct->ct_length) { PyErr_Format(PyExc_IndexError, "initializer unicode is too long for '%s' " "(got %zd characters)", ct->ct_name, n); return -1; } if (n != ct->ct_length) n++; _my_PyUnicode_AsWideChar(init, (wchar_t *)data, n); return 0; } #endif } else { expected = "list or tuple"; goto cannot_convert; } cannot_convert: return _convert_error(init, ct->ct_name, expected); } static int convert_struct_from_object(char *data, CTypeDescrObject *ct, PyObject *init, Py_ssize_t *optvarsize) { const char *expected; if (ct->ct_flags & CT_UNION) { Py_ssize_t n = PyObject_Size(init); if (n < 0) return -1; if (n > 1) { PyErr_Format(PyExc_ValueError, "initializer for '%s': %zd items given, but " "only one supported (use a dict if needed)", ct->ct_name, n); return -1; } } if (PyList_Check(init) || PyTuple_Check(init)) { PyObject **items = PySequence_Fast_ITEMS(init); Py_ssize_t i, n = PySequence_Fast_GET_SIZE(init); CFieldObject *cf = (CFieldObject *)ct->ct_extra; for (i=0; ict_name, n); return -1; } if (convert_vfield_from_object(data, cf, items[i], optvarsize) < 0) return -1; cf = cf->cf_next; } return 0; } if (PyDict_Check(init)) { PyObject *d_key, *d_value; Py_ssize_t i = 0; CFieldObject *cf; while (PyDict_Next(init, &i, &d_key, &d_value)) { cf = (CFieldObject *)PyDict_GetItem(ct->ct_stuff, d_key); if (cf == NULL) { PyErr_SetObject(PyExc_KeyError, d_key); return -1; } if (convert_vfield_from_object(data, cf, d_value, optvarsize) < 0) return -1; } return 0; } expected = optvarsize == NULL ? "list or tuple or dict or struct-cdata" : "list or tuple or dict"; return _convert_error(init, ct->ct_name, expected); } #ifdef __GNUC__ # if __GNUC__ >= 4 /* Don't go inlining this huge function. Needed because occasionally it gets inlined in places where is causes a warning: call to __builtin___memcpy_chk will always overflow destination buffer (which is places where the 'ct' should never represent such a large primitive type anyway). */ __attribute__((noinline)) # endif #endif static int convert_from_object(char *data, CTypeDescrObject *ct, PyObject *init) { const char *expected; char buf[sizeof(PY_LONG_LONG)]; /*if (ct->ct_size > 0)*/ /*WRITE(data, ct->ct_size)*/ if (ct->ct_flags & CT_ARRAY) { return convert_array_from_object(data, ct, init); } if (ct->ct_flags & (CT_POINTER|CT_FUNCTIONPTR)) { char *ptrdata; CTypeDescrObject *ctinit; if (!CData_Check(init)) { expected = "cdata pointer"; goto cannot_convert; } ctinit = ((CDataObject *)init)->c_type; if (!(ctinit->ct_flags & (CT_POINTER|CT_FUNCTIONPTR))) { if (ctinit->ct_flags & CT_ARRAY) ctinit = (CTypeDescrObject *)ctinit->ct_stuff; else { expected = "pointer or array"; goto cannot_convert; } } if (ctinit != ct) { if ((ct->ct_flags & CT_CAST_ANYTHING) || (ctinit->ct_flags & CT_CAST_ANYTHING)) ; /* accept void* or char* as either source or target */ else { expected = "pointer to same type"; goto cannot_convert; } } ptrdata = ((CDataObject *)init)->c_data; *(char **)data = ptrdata; return 0; } if (ct->ct_flags & CT_PRIMITIVE_SIGNED) { PY_LONG_LONG value = _my_PyLong_AsLongLong(init); if (value == -1 && PyErr_Occurred()) return -1; write_raw_integer_data(buf, value, ct->ct_size); if (value != read_raw_signed_data(buf, ct->ct_size)) goto overflow; write_raw_integer_data(data, value, ct->ct_size); return 0; } if (ct->ct_flags & CT_PRIMITIVE_UNSIGNED) { unsigned PY_LONG_LONG value = _my_PyLong_AsUnsignedLongLong(init, 1); if (value == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred()) return -1; if (ct->ct_flags & CT_IS_BOOL) if (value & ~1) /* value != 0 && value != 1 */ goto overflow; write_raw_integer_data(buf, value, ct->ct_size); if (value != read_raw_unsigned_data(buf, ct->ct_size)) goto overflow; write_raw_integer_data(data, value, ct->ct_size); return 0; } if (ct->ct_flags & CT_PRIMITIVE_FLOAT) { double value; if ((ct->ct_flags & CT_IS_LONGDOUBLE) && CData_Check(init) && (((CDataObject *)init)->c_type->ct_flags & CT_IS_LONGDOUBLE)) { long double lvalue; char *initdata = ((CDataObject *)init)->c_data; /*READ(initdata, sizeof(long double))*/ lvalue = read_raw_longdouble_data(initdata); write_raw_longdouble_data(data, lvalue); return 0; } value = PyFloat_AsDouble(init); if (value == -1.0 && PyErr_Occurred()) return -1; if (!(ct->ct_flags & CT_IS_LONGDOUBLE)) write_raw_float_data(data, value, ct->ct_size); else write_raw_longdouble_data(data, (long double)value); return 0; } if (ct->ct_flags & CT_PRIMITIVE_CHAR) { if (ct->ct_size == sizeof(char)) { int res = _convert_to_char(init); if (res < 0) return -1; data[0] = res; return 0; } #ifdef HAVE_WCHAR_H else { wchar_t res = _convert_to_wchar_t(init); if (res == (wchar_t)-1 && PyErr_Occurred()) return -1; *(wchar_t *)data = res; return 0; } #endif } if (ct->ct_flags & (CT_STRUCT|CT_UNION)) { if (CData_Check(init)) { if (((CDataObject *)init)->c_type == ct && ct->ct_size >= 0) { memcpy(data, ((CDataObject *)init)->c_data, ct->ct_size); return 0; } } return convert_struct_from_object(data, ct, init, NULL); } PyErr_Format(PyExc_SystemError, "convert_from_object: '%s'", ct->ct_name); return -1; overflow: return _convert_overflow(init, ct->ct_name); cannot_convert: return _convert_error(init, ct->ct_name, expected); } static int convert_from_object_bitfield(char *data, CFieldObject *cf, PyObject *init) { CTypeDescrObject *ct = cf->cf_type; PY_LONG_LONG fmin, fmax, value = PyLong_AsLongLong(init); unsigned PY_LONG_LONG rawfielddata, rawvalue, rawmask; if (value == -1 && PyErr_Occurred()) return -1; if (ct->ct_flags & CT_PRIMITIVE_SIGNED) { fmin = -(1LL << (cf->cf_bitsize-1)); fmax = (1LL << (cf->cf_bitsize-1)) - 1LL; if (fmax == 0) fmax = 1; /* special case to let "int x:1" receive "1" */ } else { fmin = 0LL; fmax = (PY_LONG_LONG)((1ULL << cf->cf_bitsize) - 1ULL); } if (value < fmin || value > fmax) { /* phew, PyErr_Format does not support "%lld" in Python 2.6 */ PyObject *svalue = NULL, *sfmin = NULL, *sfmax = NULL; PyObject *lfmin = NULL, *lfmax = NULL; svalue = PyObject_Str(init); if (svalue == NULL) goto skip; lfmin = PyLong_FromLongLong(fmin); if (lfmin == NULL) goto skip; sfmin = PyObject_Str(lfmin); if (sfmin == NULL) goto skip; lfmax = PyLong_FromLongLong(fmax); if (lfmax == NULL) goto skip; sfmax = PyObject_Str(lfmax); if (sfmax == NULL) goto skip; PyErr_Format(PyExc_OverflowError, "value %s outside the range allowed by the " "bit field width: %s <= x <= %s", PyText_AS_UTF8(svalue), PyText_AS_UTF8(sfmin), PyText_AS_UTF8(sfmax)); skip: Py_XDECREF(svalue); Py_XDECREF(sfmin); Py_XDECREF(sfmax); Py_XDECREF(lfmin); Py_XDECREF(lfmax); return -1; } rawmask = ((1ULL << cf->cf_bitsize) - 1ULL) << cf->cf_bitshift; rawvalue = ((unsigned PY_LONG_LONG)value) << cf->cf_bitshift; /*WRITE(data, ct->ct_size)*/ rawfielddata = read_raw_unsigned_data(data, ct->ct_size); rawfielddata = (rawfielddata & ~rawmask) | (rawvalue & rawmask); write_raw_integer_data(data, rawfielddata, ct->ct_size); return 0; } static Py_ssize_t get_array_length(CDataObject *cd) { if (cd->c_type->ct_length < 0) return ((CDataObject_own_length *)cd)->length; else return cd->c_type->ct_length; } static int get_alignment(CTypeDescrObject *ct) { int align; retry: if ((ct->ct_flags & (CT_PRIMITIVE_ANY|CT_STRUCT|CT_UNION)) && !(ct->ct_flags & CT_IS_OPAQUE)) { align = ct->ct_length; } else if (ct->ct_flags & (CT_POINTER|CT_FUNCTIONPTR)) { struct aligncheck_ptr { char x; char *y; }; align = offsetof(struct aligncheck_ptr, y); } else if (ct->ct_flags & CT_ARRAY) { ct = ct->ct_itemdescr; goto retry; } else { PyErr_Format(PyExc_ValueError, "ctype '%s' is of unknown alignment", ct->ct_name); return -1; } if ((align < 1) || (align & (align-1))) { PyErr_Format(PyExc_SystemError, "found for ctype '%s' bogus alignment '%d'", ct->ct_name, align); return -1; } return align; } static void cdata_dealloc(CDataObject *cd) { if (cd->c_weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *) cd); Py_DECREF(cd->c_type); #ifndef CFFI_MEM_LEAK /* never release anything, tests only */ Py_TYPE(cd)->tp_free((PyObject *)cd); #endif } static void cdataowning_dealloc(CDataObject *cd) { assert(!(cd->c_type->ct_flags & (CT_IS_VOID_PTR | CT_FUNCTIONPTR))); if (cd->c_type->ct_flags & CT_IS_PTR_TO_OWNED) { Py_DECREF(((CDataObject_own_structptr *)cd)->structobj); } #if defined(CFFI_MEM_DEBUG) || defined(CFFI_MEM_LEAK) if (cd->c_type->ct_flags & (CT_PRIMITIVE_ANY | CT_STRUCT | CT_UNION)) { assert(cd->c_type->ct_size >= 0); memset(cd->c_data, 0xDD, cd->c_type->ct_size); } else if (cd->c_type->ct_flags & CT_ARRAY) { Py_ssize_t x = get_array_length(cd); assert(x >= 0); x *= cd->c_type->ct_itemdescr->ct_size; assert(x >= 0); memset(cd->c_data, 0xDD, x); } #endif cdata_dealloc(cd); } static void cdataowninggc_dealloc(CDataObject *cd) { assert(!(cd->c_type->ct_flags & (CT_IS_PTR_TO_OWNED | CT_PRIMITIVE_ANY | CT_STRUCT | CT_UNION))); PyObject_GC_UnTrack(cd); if (cd->c_type->ct_flags & CT_IS_VOID_PTR) { /* a handle */ PyObject *x = (PyObject *)(cd->c_data + 42); Py_DECREF(x); } else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) { /* a callback */ ffi_closure *closure = (ffi_closure *)cd->c_data; PyObject *args = (PyObject *)(closure->user_data); Py_XDECREF(args); cffi_closure_free(closure); } cdata_dealloc(cd); } static int cdataowninggc_traverse(CDataObject *cd, visitproc visit, void *arg) { if (cd->c_type->ct_flags & CT_IS_VOID_PTR) { /* a handle */ PyObject *x = (PyObject *)(cd->c_data + 42); Py_VISIT(x); } else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) { /* a callback */ ffi_closure *closure = (ffi_closure *)cd->c_data; PyObject *args = (PyObject *)(closure->user_data); Py_VISIT(args); } return 0; } static int cdataowninggc_clear(CDataObject *cd) { if (cd->c_type->ct_flags & CT_IS_VOID_PTR) { /* a handle */ PyObject *x = (PyObject *)(cd->c_data + 42); Py_INCREF(Py_None); cd->c_data = ((char *)Py_None) - 42; Py_DECREF(x); } else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) { /* a callback */ ffi_closure *closure = (ffi_closure *)cd->c_data; PyObject *args = (PyObject *)(closure->user_data); closure->user_data = NULL; Py_XDECREF(args); } return 0; } static PyObject *cdata_float(CDataObject *cd); /*forward*/ static PyObject *convert_cdata_to_enum_string(CDataObject *cd, int both) { PyObject *d_key, *d_value; CTypeDescrObject *ct = cd->c_type; assert(ct->ct_flags & CT_IS_ENUM); d_key = convert_to_object(cd->c_data, ct); if (d_key == NULL) return NULL; d_value = PyDict_GetItem(PyTuple_GET_ITEM(ct->ct_stuff, 1), d_key); if (d_value != NULL) { if (both) { PyObject *o = PyObject_Str(d_key); if (o == NULL) d_value = NULL; else { d_value = PyText_FromFormat("%s: %s", PyText_AS_UTF8(o), PyText_AS_UTF8(d_value)); Py_DECREF(o); } } else Py_INCREF(d_value); } else d_value = PyObject_Str(d_key); Py_DECREF(d_key); return d_value; } static PyObject *cdata_repr(CDataObject *cd) { char *extra; PyObject *result, *s; if (cd->c_type->ct_flags & CT_PRIMITIVE_ANY) { if (cd->c_type->ct_flags & CT_IS_ENUM) { s = convert_cdata_to_enum_string(cd, 1); } else if (cd->c_type->ct_flags & CT_IS_LONGDOUBLE) { long double lvalue; char buffer[128]; /* big enough */ /*READ(cd->c_data, sizeof(long double)*/ lvalue = read_raw_longdouble_data(cd->c_data); sprintf(buffer, "%LE", lvalue); s = PyText_FromString(buffer); } else { PyObject *o = convert_to_object(cd->c_data, cd->c_type); if (o == NULL) return NULL; s = PyObject_Repr(o); Py_DECREF(o); } } else if ((cd->c_type->ct_flags & CT_ARRAY) && cd->c_type->ct_length < 0) { s = PyText_FromFormat("sliced length %zd", get_array_length(cd)); } else { if (cd->c_data != NULL) { s = PyText_FromFormat("%p", cd->c_data); } else s = PyText_FromString("NULL"); } if (s == NULL) return NULL; /* it's slightly confusing to get "" because the struct foo is not owned. Trying to make it clearer, write in this case "". */ if (cd->c_type->ct_flags & (CT_STRUCT|CT_UNION)) extra = " &"; else extra = ""; result = PyText_FromFormat("", cd->c_type->ct_name, extra, PyText_AsUTF8(s)); Py_DECREF(s); return result; } static PyObject *_cdata_repr2(CDataObject *cd, char *text, PyObject *x) { PyObject *res, *s = PyObject_Repr(x); if (s == NULL) return NULL; res = PyText_FromFormat("", cd->c_type->ct_name, text, PyText_AsUTF8(s)); Py_DECREF(s); return res; } static PyObject *cdataowning_repr(CDataObject *cd) { Py_ssize_t size; if (cd->c_type->ct_flags & CT_POINTER) { if (cd->c_type->ct_flags & CT_IS_VOID_PTR) goto handle_repr; size = cd->c_type->ct_itemdescr->ct_size; } else if (cd->c_type->ct_flags & CT_ARRAY) size = get_array_length(cd) * cd->c_type->ct_itemdescr->ct_size; else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) goto callback_repr; else size = cd->c_type->ct_size; return PyText_FromFormat("", cd->c_type->ct_name, size); callback_repr: { PyObject *args = (PyObject *)((ffi_closure *)cd->c_data)->user_data; if (args == NULL) return cdata_repr(cd); else return _cdata_repr2(cd, "calling", PyTuple_GET_ITEM(args, 1)); } handle_repr: { PyObject *x = (PyObject *)(cd->c_data + 42); return _cdata_repr2(cd, "handle to", x); } } static int cdata_nonzero(CDataObject *cd) { return cd->c_data != NULL; } static PyObject *cdata_int(CDataObject *cd) { if ((cd->c_type->ct_flags & (CT_PRIMITIVE_SIGNED|CT_PRIMITIVE_FITS_LONG)) == (CT_PRIMITIVE_SIGNED|CT_PRIMITIVE_FITS_LONG)) { /* this case is to handle enums, but also serves as a slight performance improvement for some other primitive types */ long value; /*READ(cd->c_data, cd->c_type->ct_size)*/ value = (long)read_raw_signed_data(cd->c_data, cd->c_type->ct_size); return PyInt_FromLong(value); } if (cd->c_type->ct_flags & (CT_PRIMITIVE_SIGNED|CT_PRIMITIVE_UNSIGNED)) { return convert_to_object(cd->c_data, cd->c_type); } else if (cd->c_type->ct_flags & CT_PRIMITIVE_CHAR) { /*READ(cd->c_data, cd->c_type->ct_size)*/ if (cd->c_type->ct_size == sizeof(char)) return PyInt_FromLong((unsigned char)cd->c_data[0]); #ifdef HAVE_WCHAR_H else return PyInt_FromLong((long)*(wchar_t *)cd->c_data); #endif } else if (cd->c_type->ct_flags & CT_PRIMITIVE_FLOAT) { PyObject *o = cdata_float(cd); #if PY_MAJOR_VERSION < 3 PyObject *r = o ? PyNumber_Int(o) : NULL; #else PyObject *r = o ? PyNumber_Long(o) : NULL; #endif Py_XDECREF(o); return r; } PyErr_Format(PyExc_TypeError, "int() not supported on cdata '%s'", cd->c_type->ct_name); return NULL; } #if PY_MAJOR_VERSION < 3 static PyObject *cdata_long(CDataObject *cd) { PyObject *res = cdata_int(cd); if (res != NULL && PyInt_CheckExact(res)) { PyObject *o = PyLong_FromLong(PyInt_AS_LONG(res)); Py_DECREF(res); res = o; } return res; } #endif static PyObject *cdata_float(CDataObject *cd) { if (cd->c_type->ct_flags & CT_PRIMITIVE_FLOAT) { double value; /*READ(cd->c_data, cd->c_type->ct_size)*/ if (!(cd->c_type->ct_flags & CT_IS_LONGDOUBLE)) { value = read_raw_float_data(cd->c_data, cd->c_type->ct_size); } else { value = (double)read_raw_longdouble_data(cd->c_data); } return PyFloat_FromDouble(value); } PyErr_Format(PyExc_TypeError, "float() not supported on cdata '%s'", cd->c_type->ct_name); return NULL; } static PyObject *cdata_richcompare(PyObject *v, PyObject *w, int op) { int res; PyObject *pyres; char *v_cdata, *w_cdata; assert(CData_Check(v)); if (!CData_Check(w)) { pyres = Py_NotImplemented; goto done; } if ((op != Py_EQ && op != Py_NE) && ((((CDataObject *)v)->c_type->ct_flags & CT_PRIMITIVE_ANY) || (((CDataObject *)w)->c_type->ct_flags & CT_PRIMITIVE_ANY))) goto Error; v_cdata = ((CDataObject *)v)->c_data; w_cdata = ((CDataObject *)w)->c_data; switch (op) { case Py_EQ: res = (v_cdata == w_cdata); break; case Py_NE: res = (v_cdata != w_cdata); break; case Py_LT: res = (v_cdata < w_cdata); break; case Py_LE: res = (v_cdata <= w_cdata); break; case Py_GT: res = (v_cdata > w_cdata); break; case Py_GE: res = (v_cdata >= w_cdata); break; default: res = -1; } pyres = res ? Py_True : Py_False; done: Py_INCREF(pyres); return pyres; Error: PyErr_SetString(PyExc_TypeError, "cannot do comparison on a primitive cdata"); return NULL; } static long cdata_hash(CDataObject *cd) { return _Py_HashPointer(cd->c_data); } static Py_ssize_t cdata_length(CDataObject *cd) { if (cd->c_type->ct_flags & CT_ARRAY) { return get_array_length(cd); } PyErr_Format(PyExc_TypeError, "cdata of type '%s' has no len()", cd->c_type->ct_name); return -1; } static char * _cdata_get_indexed_ptr(CDataObject *cd, PyObject *key) { Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError); if (i == -1 && PyErr_Occurred()) return NULL; if (cd->c_type->ct_flags & CT_POINTER) { if (CDataOwn_Check(cd) && i != 0) { PyErr_Format(PyExc_IndexError, "cdata '%s' can only be indexed by 0", cd->c_type->ct_name); return NULL; } } else if (cd->c_type->ct_flags & CT_ARRAY) { if (i < 0) { PyErr_SetString(PyExc_IndexError, "negative index not supported"); return NULL; } if (i >= get_array_length(cd)) { PyErr_Format(PyExc_IndexError, "index too large for cdata '%s' (expected %zd < %zd)", cd->c_type->ct_name, i, get_array_length(cd)); return NULL; } } else { PyErr_Format(PyExc_TypeError, "cdata of type '%s' cannot be indexed", cd->c_type->ct_name); return NULL; } return cd->c_data + i * cd->c_type->ct_itemdescr->ct_size; } static PyObject * new_array_type(CTypeDescrObject *ctptr, PyObject *lengthobj); /* forward */ static CTypeDescrObject * _cdata_getslicearg(CDataObject *cd, PySliceObject *slice, Py_ssize_t bounds[]) { Py_ssize_t start, stop; CTypeDescrObject *ct; start = PyInt_AsSsize_t(slice->start); if (start == -1 && PyErr_Occurred()) { if (slice->start == Py_None) PyErr_SetString(PyExc_IndexError, "slice start must be specified"); return NULL; } stop = PyInt_AsSsize_t(slice->stop); if (stop == -1 && PyErr_Occurred()) { if (slice->stop == Py_None) PyErr_SetString(PyExc_IndexError, "slice stop must be specified"); return NULL; } if (slice->step != Py_None) { PyErr_SetString(PyExc_IndexError, "slice with step not supported"); return NULL; } if (start > stop) { PyErr_SetString(PyExc_IndexError, "slice start > stop"); return NULL; } ct = cd->c_type; if (ct->ct_flags & CT_ARRAY) { if (start < 0) { PyErr_SetString(PyExc_IndexError, "negative index not supported"); return NULL; } if (stop > get_array_length(cd)) { PyErr_Format(PyExc_IndexError, "index too large (expected %zd <= %zd)", stop, get_array_length(cd)); return NULL; } ct = (CTypeDescrObject *)ct->ct_stuff; } else if (!(ct->ct_flags & CT_POINTER)) { PyErr_Format(PyExc_TypeError, "cdata of type '%s' cannot be indexed", ct->ct_name); return NULL; } bounds[0] = start; bounds[1] = stop - start; return ct; } static PyObject * cdata_slice(CDataObject *cd, PySliceObject *slice) { Py_ssize_t bounds[2]; CDataObject_own_length *scd; CTypeDescrObject *ct = _cdata_getslicearg(cd, slice, bounds); if (ct == NULL) return NULL; if (ct->ct_stuff == NULL) { ct->ct_stuff = new_array_type(ct, Py_None); if (ct->ct_stuff == NULL) return NULL; } ct = (CTypeDescrObject *)ct->ct_stuff; scd = (CDataObject_own_length *)PyObject_Malloc( offsetof(CDataObject_own_length, alignment)); if (PyObject_Init((PyObject *)scd, &CData_Type) == NULL) return NULL; Py_INCREF(ct); scd->head.c_type = ct; scd->head.c_data = cd->c_data + ct->ct_itemdescr->ct_size * bounds[0]; scd->head.c_weakreflist = NULL; scd->length = bounds[1]; return (PyObject *)scd; } static int cdata_ass_slice(CDataObject *cd, PySliceObject *slice, PyObject *v) { Py_ssize_t bounds[2], i, length, itemsize; PyObject *it, *item; PyObject *(*iternext)(PyObject *); char *cdata; int err; CTypeDescrObject *ct = _cdata_getslicearg(cd, slice, bounds); if (ct == NULL) return -1; ct = ct->ct_itemdescr; itemsize = ct->ct_size; cdata = cd->c_data + itemsize * bounds[0]; length = bounds[1]; if (CData_Check(v)) { CTypeDescrObject *ctv = ((CDataObject *)v)->c_type; if ((ctv->ct_flags & CT_ARRAY) && (ctv->ct_itemdescr == ct) && (get_array_length((CDataObject *)v) == length)) { /* fast path: copying from exactly the correct type */ memmove(cdata, ((CDataObject *)v)->c_data, itemsize * length); return 0; } } /* A fast path for [0:N] = b"somestring", which also adds support for Python 3: otherwise, you get integers while enumerating the string, and you can't set them to characters :-/ */ if (PyBytes_Check(v) && (ct->ct_flags & CT_PRIMITIVE_CHAR) && itemsize == sizeof(char)) { if (PyBytes_GET_SIZE(v) != length) { PyErr_Format(PyExc_ValueError, "need a string of length %zd, got %zd", length, PyBytes_GET_SIZE(v)); return -1; } memcpy(cdata, PyBytes_AS_STRING(v), length); return 0; } it = PyObject_GetIter(v); if (it == NULL) return -1; iternext = *it->ob_type->tp_iternext; for (i = 0; i < length; i++) { item = iternext(it); if (item == NULL) { if (!PyErr_Occurred()) PyErr_Format(PyExc_ValueError, "need %zd values to unpack, got %zd", length, i); goto error; } err = convert_from_object(cdata, ct, item); Py_DECREF(item); if (err < 0) goto error; cdata += itemsize; } item = iternext(it); if (item != NULL) { Py_DECREF(item); PyErr_Format(PyExc_ValueError, "got more than %zd values to unpack", length); } error: Py_DECREF(it); return PyErr_Occurred() ? -1 : 0; } static PyObject * cdataowning_subscript(CDataObject *cd, PyObject *key) { char *c; if (PySlice_Check(key)) return cdata_slice(cd, (PySliceObject *)key); c = _cdata_get_indexed_ptr(cd, key); /* use 'mp_subscript' instead of 'sq_item' because we don't want negative indexes to be corrected automatically */ if (c == NULL && PyErr_Occurred()) return NULL; if (cd->c_type->ct_flags & CT_IS_PTR_TO_OWNED) { PyObject *res = ((CDataObject_own_structptr *)cd)->structobj; Py_INCREF(res); return res; } else { return convert_to_object(c, cd->c_type->ct_itemdescr); } } static PyObject * cdata_subscript(CDataObject *cd, PyObject *key) { char *c; if (PySlice_Check(key)) return cdata_slice(cd, (PySliceObject *)key); c = _cdata_get_indexed_ptr(cd, key); /* use 'mp_subscript' instead of 'sq_item' because we don't want negative indexes to be corrected automatically */ if (c == NULL && PyErr_Occurred()) return NULL; return convert_to_object(c, cd->c_type->ct_itemdescr); } static int cdata_ass_sub(CDataObject *cd, PyObject *key, PyObject *v) { char *c; CTypeDescrObject *ctitem; if (PySlice_Check(key)) return cdata_ass_slice(cd, (PySliceObject *)key, v); c = _cdata_get_indexed_ptr(cd, key); ctitem = cd->c_type->ct_itemdescr; /* use 'mp_ass_subscript' instead of 'sq_ass_item' because we don't want negative indexes to be corrected automatically */ if (c == NULL && PyErr_Occurred()) return -1; if (v == NULL) { PyErr_SetString(PyExc_TypeError, "'del x[n]' not supported for cdata objects"); return -1; } return convert_from_object(c, ctitem, v); } static PyObject * _cdata_add_or_sub(PyObject *v, PyObject *w, int sign) { Py_ssize_t i, itemsize; CDataObject *cd; CTypeDescrObject *ctptr; if (!CData_Check(v)) { PyObject *swap; assert(CData_Check(w)); if (sign != 1) goto not_implemented; swap = v; v = w; w = swap; } i = PyNumber_AsSsize_t(w, PyExc_OverflowError); if (i == -1 && PyErr_Occurred()) return NULL; i *= sign; cd = (CDataObject *)v; if (cd->c_type->ct_flags & CT_POINTER) ctptr = cd->c_type; else if (cd->c_type->ct_flags & CT_ARRAY) { ctptr = (CTypeDescrObject *)cd->c_type->ct_stuff; } else { PyErr_Format(PyExc_TypeError, "cannot add a cdata '%s' and a number", cd->c_type->ct_name); return NULL; } itemsize = ctptr->ct_itemdescr->ct_size; if (itemsize < 0) { if (ctptr->ct_flags & CT_IS_VOID_PTR) { itemsize = 1; } else { PyErr_Format(PyExc_TypeError, "ctype '%s' points to items of unknown size", cd->c_type->ct_name); return NULL; } } return new_simple_cdata(cd->c_data + i * itemsize, ctptr); not_implemented: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } static PyObject * cdata_add(PyObject *v, PyObject *w) { return _cdata_add_or_sub(v, w, +1); } static PyObject * cdata_sub(PyObject *v, PyObject *w) { if (CData_Check(v) && CData_Check(w)) { CDataObject *cdv = (CDataObject *)v; CDataObject *cdw = (CDataObject *)w; CTypeDescrObject *ct = cdw->c_type; Py_ssize_t diff, itemsize; if (ct->ct_flags & CT_ARRAY) /* ptr_to_T - array_of_T: ok */ ct = (CTypeDescrObject *)ct->ct_stuff; if (ct != cdv->c_type || !(ct->ct_flags & CT_POINTER) || (ct->ct_itemdescr->ct_size <= 0 && !(ct->ct_flags & CT_IS_VOID_PTR))) { PyErr_Format(PyExc_TypeError, "cannot subtract cdata '%s' and cdata '%s'", cdv->c_type->ct_name, ct->ct_name); return NULL; } itemsize = ct->ct_itemdescr->ct_size; if (itemsize <= 0) itemsize = 1; diff = (cdv->c_data - cdw->c_data) / itemsize; #if PY_MAJOR_VERSION < 3 return PyInt_FromSsize_t(diff); #else return PyLong_FromSsize_t(diff); #endif } return _cdata_add_or_sub(v, w, -1); } static PyObject * cdata_getattro(CDataObject *cd, PyObject *attr) { CFieldObject *cf; CTypeDescrObject *ct = cd->c_type; if (ct->ct_flags & CT_POINTER) ct = ct->ct_itemdescr; if ((ct->ct_flags & (CT_STRUCT|CT_UNION)) && ct->ct_stuff != NULL) { cf = (CFieldObject *)PyDict_GetItem(ct->ct_stuff, attr); if (cf != NULL) { /* read the field 'cf' */ char *data = cd->c_data + cf->cf_offset; if (cf->cf_bitshift == BS_REGULAR) return convert_to_object(data, cf->cf_type); else if (cf->cf_bitshift == BS_EMPTY_ARRAY) return new_simple_cdata(data, (CTypeDescrObject *)cf->cf_type->ct_stuff); else return convert_to_object_bitfield(data, cf); } } return PyObject_GenericGetAttr((PyObject *)cd, attr); } static int cdata_setattro(CDataObject *cd, PyObject *attr, PyObject *value) { CFieldObject *cf; CTypeDescrObject *ct = cd->c_type; if (ct->ct_flags & CT_POINTER) ct = ct->ct_itemdescr; if ((ct->ct_flags & (CT_STRUCT|CT_UNION)) && ct->ct_stuff != NULL) { cf = (CFieldObject *)PyDict_GetItem(ct->ct_stuff, attr); if (cf != NULL) { /* write the field 'cf' */ if (value != NULL) { return convert_field_from_object(cd->c_data, cf, value); } else { PyErr_SetString(PyExc_AttributeError, "cannot delete struct field"); return -1; } } } return PyObject_GenericSetAttr((PyObject *)cd, attr, value); } static PyObject * convert_struct_to_owning_object(char *data, CTypeDescrObject *ct); /*forward*/ static cif_description_t * fb_prepare_cif(PyObject *fargs, CTypeDescrObject *, ffi_abi); /*forward*/ static PyObject * b_new_primitive_type(PyObject *self, PyObject *args); /*forward*/ static CTypeDescrObject *_get_ct_int(void) { static CTypeDescrObject *ct_int = NULL; if (ct_int == NULL) { PyObject *args = Py_BuildValue("(s)", "int"); if (args == NULL) return NULL; ct_int = (CTypeDescrObject *)b_new_primitive_type(NULL, args); Py_DECREF(args); } return ct_int; } static Py_ssize_t _prepare_pointer_call_argument(CTypeDescrObject *ctptr, PyObject *init, char **output_data) { /* 'ctptr' is here a pointer type 'ITEM *'. Accept as argument an initializer for an array 'ITEM[]'. This includes the case of passing a Python byte string to a 'char *' argument. This function returns -1 if an error occurred, 0 if conversion succeeded (into *output_data), or N > 0 if conversion would require N bytes of storage. */ Py_ssize_t length, datasize; CTypeDescrObject *ctitem; if (CData_Check(init)) goto convert_default; ctitem = ctptr->ct_itemdescr; /* XXX some code duplication, how to avoid it? */ if (PyBytes_Check(init)) { /* from a string: just returning the string here is fine. We assume that the C code won't modify the 'char *' data. */ if ((ctptr->ct_flags & CT_CAST_ANYTHING) || ((ctitem->ct_flags & (CT_PRIMITIVE_SIGNED|CT_PRIMITIVE_UNSIGNED)) && (ctitem->ct_size == sizeof(char)))) { #if defined(CFFI_MEM_DEBUG) || defined(CFFI_MEM_LEAK) length = PyBytes_GET_SIZE(init) + 1; #else *output_data = PyBytes_AS_STRING(init); return 0; #endif } else goto convert_default; } else if (PyList_Check(init) || PyTuple_Check(init)) { length = PySequence_Fast_GET_SIZE(init); } else if (PyUnicode_Check(init)) { /* from a unicode, we add the null terminator */ length = _my_PyUnicode_SizeAsWideChar(init) + 1; } else if ((ctitem->ct_flags & CT_IS_FILE) && PyFile_Check(init)) { *output_data = (char *)PyFile_AsFile(init); if (*output_data == NULL && PyErr_Occurred()) return -1; return 0; } else { /* refuse to receive just an integer (and interpret it as the array size) */ goto convert_default; } if (ctitem->ct_size <= 0) goto convert_default; datasize = length * ctitem->ct_size; if ((datasize / ctitem->ct_size) != length) { PyErr_SetString(PyExc_OverflowError, "array size would overflow a Py_ssize_t"); return -1; } if (datasize <= 0) datasize = 1; return datasize; convert_default: return convert_from_object((char *)output_data, ctptr, init); } static PyObject* cdata_call(CDataObject *cd, PyObject *args, PyObject *kwds) { char *buffer; void** buffer_array; cif_description_t *cif_descr; Py_ssize_t i, nargs, nargs_declared; PyObject *signature, *res = NULL, *fvarargs; CTypeDescrObject *fresult; char *resultdata; char *errormsg; if (!(cd->c_type->ct_flags & CT_FUNCTIONPTR)) { PyErr_Format(PyExc_TypeError, "cdata '%s' is not callable", cd->c_type->ct_name); return NULL; } if (kwds != NULL && PyDict_Size(kwds) != 0) { PyErr_SetString(PyExc_TypeError, "a cdata function cannot be called with keyword arguments"); return NULL; } signature = cd->c_type->ct_stuff; nargs = PyTuple_Size(args); if (nargs < 0) return NULL; nargs_declared = PyTuple_GET_SIZE(signature) - 2; fresult = (CTypeDescrObject *)PyTuple_GET_ITEM(signature, 1); fvarargs = NULL; buffer = NULL; cif_descr = (cif_description_t *)cd->c_type->ct_extra; if (cif_descr != NULL) { /* regular case: this function does not take '...' arguments */ if (nargs != nargs_declared) { errormsg = "'%s' expects %zd arguments, got %zd"; bad_number_of_arguments: PyErr_Format(PyExc_TypeError, errormsg, cd->c_type->ct_name, nargs_declared, nargs); goto error; } } else { /* call of a variadic function */ ffi_abi fabi; if (nargs < nargs_declared) { errormsg = "'%s' expects at least %zd arguments, got %zd"; goto bad_number_of_arguments; } fvarargs = PyTuple_New(nargs); if (fvarargs == NULL) goto error; for (i = 0; i < nargs_declared; i++) { PyObject *o = PyTuple_GET_ITEM(signature, 2 + i); Py_INCREF(o); PyTuple_SET_ITEM(fvarargs, i, o); } for (i = nargs_declared; i < nargs; i++) { PyObject *obj = PyTuple_GET_ITEM(args, i); CTypeDescrObject *ct; if (CData_Check(obj)) { ct = ((CDataObject *)obj)->c_type; if (ct->ct_flags & (CT_PRIMITIVE_CHAR | CT_PRIMITIVE_UNSIGNED | CT_PRIMITIVE_SIGNED)) { if (ct->ct_size < sizeof(int)) { ct = _get_ct_int(); if (ct == NULL) goto error; } } else if (ct->ct_flags & CT_ARRAY) { ct = (CTypeDescrObject *)ct->ct_stuff; } Py_INCREF(ct); } else { PyErr_Format(PyExc_TypeError, "argument %zd passed in the variadic part " "needs to be a cdata object (got %.200s)", i + 1, Py_TYPE(obj)->tp_name); goto error; } PyTuple_SET_ITEM(fvarargs, i, (PyObject *)ct); } #if PY_MAJOR_VERSION < 3 fabi = PyInt_AS_LONG(PyTuple_GET_ITEM(signature, 0)); #else fabi = PyLong_AS_LONG(PyTuple_GET_ITEM(signature, 0)); #endif cif_descr = fb_prepare_cif(fvarargs, fresult, fabi); if (cif_descr == NULL) goto error; } buffer = PyObject_Malloc(cif_descr->exchange_size); if (buffer == NULL) { PyErr_NoMemory(); goto error; } buffer_array = (void **)buffer; for (i=0; iexchange_offset_arg[1 + i]; PyObject *obj = PyTuple_GET_ITEM(args, i); buffer_array[i] = data; if (i < nargs_declared) argtype = (CTypeDescrObject *)PyTuple_GET_ITEM(signature, 2 + i); else argtype = (CTypeDescrObject *)PyTuple_GET_ITEM(fvarargs, i); if (argtype->ct_flags & CT_POINTER) { char *tmpbuf; Py_ssize_t datasize = _prepare_pointer_call_argument( argtype, obj, (char **)data); if (datasize == 0) ; /* successfully filled '*data' */ else if (datasize < 0) goto error; else { tmpbuf = alloca(datasize); memset(tmpbuf, 0, datasize); *(char **)data = tmpbuf; if (convert_array_from_object(tmpbuf, argtype, obj) < 0) goto error; } } else if (convert_from_object(data, argtype, obj) < 0) goto error; } resultdata = buffer + cif_descr->exchange_offset_arg[0]; /*READ(cd->c_data, sizeof(void(*)(void)))*/ Py_BEGIN_ALLOW_THREADS restore_errno(); ffi_call(&cif_descr->cif, (void (*)(void))(cd->c_data), resultdata, buffer_array); save_errno(); Py_END_ALLOW_THREADS if (fresult->ct_flags & (CT_PRIMITIVE_CHAR | CT_PRIMITIVE_SIGNED | CT_PRIMITIVE_UNSIGNED)) { #ifdef WORDS_BIGENDIAN /* For results of precisely these types, libffi has a strange rule that they will be returned as a whole 'ffi_arg' if they are smaller. The difference only matters on big-endian. */ if (fresult->ct_size < sizeof(ffi_arg)) resultdata += (sizeof(ffi_arg) - fresult->ct_size); #endif res = convert_to_object(resultdata, fresult); } else if (fresult->ct_flags & CT_VOID) { res = Py_None; Py_INCREF(res); } else if (fresult->ct_flags & CT_STRUCT) { res = convert_struct_to_owning_object(resultdata, fresult); } else { res = convert_to_object(resultdata, fresult); } /* fall-through */ error: if (buffer) PyObject_Free(buffer); if (fvarargs != NULL) { Py_DECREF(fvarargs); if (cif_descr != NULL) /* but only if fvarargs != NULL, if variadic */ PyObject_Free(cif_descr); } return res; } static PyObject *cdata_iter(CDataObject *); static PyNumberMethods CData_as_number = { (binaryfunc)cdata_add, /*nb_add*/ (binaryfunc)cdata_sub, /*nb_subtract*/ 0, /*nb_multiply*/ #if PY_MAJOR_VERSION < 3 0, /*nb_divide*/ #endif 0, /*nb_remainder*/ 0, /*nb_divmod*/ 0, /*nb_power*/ 0, /*nb_negative*/ 0, /*nb_positive*/ 0, /*nb_absolute*/ (inquiry)cdata_nonzero, /*nb_nonzero*/ 0, /*nb_invert*/ 0, /*nb_lshift*/ 0, /*nb_rshift*/ 0, /*nb_and*/ 0, /*nb_xor*/ 0, /*nb_or*/ #if PY_MAJOR_VERSION < 3 0, /*nb_coerce*/ #endif (unaryfunc)cdata_int, /*nb_int*/ #if PY_MAJOR_VERSION < 3 (unaryfunc)cdata_long, /*nb_long*/ #else 0, #endif (unaryfunc)cdata_float, /*nb_float*/ 0, /*nb_oct*/ 0, /*nb_hex*/ }; static PyMappingMethods CData_as_mapping = { (lenfunc)cdata_length, /*mp_length*/ (binaryfunc)cdata_subscript, /*mp_subscript*/ (objobjargproc)cdata_ass_sub, /*mp_ass_subscript*/ }; static PyMappingMethods CDataOwn_as_mapping = { (lenfunc)cdata_length, /*mp_length*/ (binaryfunc)cdataowning_subscript, /*mp_subscript*/ (objobjargproc)cdata_ass_sub, /*mp_ass_subscript*/ }; static PyTypeObject CData_Type = { PyVarObject_HEAD_INIT(NULL, 0) "_cffi_backend.CData", sizeof(CDataObject), 0, (destructor)cdata_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ (reprfunc)cdata_repr, /* tp_repr */ &CData_as_number, /* tp_as_number */ 0, /* tp_as_sequence */ &CData_as_mapping, /* tp_as_mapping */ (hashfunc)cdata_hash, /* tp_hash */ (ternaryfunc)cdata_call, /* tp_call */ 0, /* tp_str */ (getattrofunc)cdata_getattro, /* tp_getattro */ (setattrofunc)cdata_setattro, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /* tp_flags */ 0, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ cdata_richcompare, /* tp_richcompare */ offsetof(CDataObject, c_weakreflist), /* tp_weaklistoffset */ (getiterfunc)cdata_iter, /* tp_iter */ 0, /* tp_iternext */ }; static PyTypeObject CDataOwning_Type = { PyVarObject_HEAD_INIT(NULL, 0) "_cffi_backend.CDataOwn", sizeof(CDataObject), 0, (destructor)cdataowning_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ (reprfunc)cdataowning_repr, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ &CDataOwn_as_mapping, /* 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_CHECKTYPES, /* tp_flags */ 0, /* 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 */ &CData_Type, /* tp_base */ }; static PyTypeObject CDataOwningGC_Type = { PyVarObject_HEAD_INIT(NULL, 0) "_cffi_backend.CDataOwnGC", sizeof(CDataObject), 0, (destructor)cdataowninggc_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 */ 0, /* tp_call */ 0, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES /* tp_flags */ | Py_TPFLAGS_HAVE_GC, 0, /* tp_doc */ (traverseproc)cdataowninggc_traverse, /* tp_traverse */ (inquiry)cdataowninggc_clear, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ 0, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ &CDataOwning_Type, /* tp_base */ }; /************************************************************/ typedef struct { PyObject_HEAD char *di_next, *di_stop; CDataObject *di_object; CTypeDescrObject *di_itemtype; } CDataIterObject; static PyObject * cdataiter_next(CDataIterObject *it) { char *result = it->di_next; if (result != it->di_stop) { it->di_next = result + it->di_itemtype->ct_size; return convert_to_object(result, it->di_itemtype); } return NULL; } static void cdataiter_dealloc(CDataIterObject *it) { Py_DECREF(it->di_object); PyObject_Del(it); } static PyTypeObject CDataIter_Type = { PyVarObject_HEAD_INIT(NULL, 0) "_cffi_backend.CDataIter", /* tp_name */ sizeof(CDataIterObject), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor)cdataiter_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 */ 0, /* tp_call */ 0, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ 0, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ PyObject_SelfIter, /* tp_iter */ (iternextfunc)cdataiter_next, /* tp_iternext */ }; static PyObject * cdata_iter(CDataObject *cd) { CDataIterObject *it; if (!(cd->c_type->ct_flags & CT_ARRAY)) { PyErr_Format(PyExc_TypeError, "cdata '%s' does not support iteration", cd->c_type->ct_name); return NULL; } it = PyObject_New(CDataIterObject, &CDataIter_Type); if (it == NULL) return NULL; Py_INCREF(cd); it->di_object = cd; it->di_itemtype = cd->c_type->ct_itemdescr; it->di_next = cd->c_data; it->di_stop = cd->c_data + get_array_length(cd) * it->di_itemtype->ct_size; return (PyObject *)it; } /************************************************************/ static CDataObject *allocate_owning_object(Py_ssize_t size, CTypeDescrObject *ct) { CDataObject *cd; cd = (CDataObject *)PyObject_Malloc(size); if (PyObject_Init((PyObject *)cd, &CDataOwning_Type) == NULL) return NULL; Py_INCREF(ct); cd->c_type = ct; cd->c_weakreflist = NULL; return cd; } static PyObject * convert_struct_to_owning_object(char *data, CTypeDescrObject *ct) { CDataObject *cd; Py_ssize_t dataoffset = offsetof(CDataObject_own_nolength, alignment); Py_ssize_t datasize = ct->ct_size; if ((ct->ct_flags & (CT_STRUCT|CT_IS_OPAQUE)) != CT_STRUCT) { PyErr_SetString(PyExc_TypeError, "return type is not a struct or is opaque"); return NULL; } cd = allocate_owning_object(dataoffset + datasize, ct); if (cd == NULL) return NULL; cd->c_data = ((char *)cd) + dataoffset; memcpy(cd->c_data, data, datasize); return (PyObject *)cd; } static PyObject *b_newp(PyObject *self, PyObject *args) { CTypeDescrObject *ct, *ctitem; CDataObject *cd; PyObject *init = Py_None; Py_ssize_t dataoffset, datasize, explicitlength; if (!PyArg_ParseTuple(args, "O!|O:newp", &CTypeDescr_Type, &ct, &init)) return NULL; explicitlength = -1; if (ct->ct_flags & CT_POINTER) { dataoffset = offsetof(CDataObject_own_nolength, alignment); ctitem = ct->ct_itemdescr; datasize = ctitem->ct_size; if (datasize < 0) { PyErr_Format(PyExc_TypeError, "cannot instantiate ctype '%s' of unknown size", ctitem->ct_name); return NULL; } if (ctitem->ct_flags & CT_PRIMITIVE_CHAR) datasize *= 2; /* forcefully add another character: a null */ if ((ctitem->ct_flags & CT_WITH_VAR_ARRAY) && init != Py_None) { Py_ssize_t optvarsize = datasize; if (convert_struct_from_object(NULL,ctitem, init, &optvarsize) < 0) return NULL; datasize = optvarsize; } } else if (ct->ct_flags & CT_ARRAY) { dataoffset = offsetof(CDataObject_own_nolength, alignment); datasize = ct->ct_size; if (datasize < 0) { explicitlength = get_new_array_length(&init); if (explicitlength < 0) return NULL; ctitem = ct->ct_itemdescr; dataoffset = offsetof(CDataObject_own_length, alignment); datasize = explicitlength * ctitem->ct_size; if (explicitlength > 0 && (datasize / explicitlength) != ctitem->ct_size) { PyErr_SetString(PyExc_OverflowError, "array size would overflow a Py_ssize_t"); return NULL; } } } else { PyErr_Format(PyExc_TypeError, "expected a pointer or array ctype, got '%s'", ct->ct_name); return NULL; } if (ct->ct_flags & CT_IS_PTR_TO_OWNED) { /* common case of ptr-to-struct (or ptr-to-union): for this case we build two objects instead of one, with the memory-owning one being really the struct (or union) and the returned one having a strong reference to it */ CDataObject *cds; cds = allocate_owning_object(dataoffset + datasize, ct->ct_itemdescr); if (cds == NULL) return NULL; cd = allocate_owning_object(sizeof(CDataObject_own_structptr), ct); if (cd == NULL) { Py_DECREF(cds); return NULL; } /* store the only reference to cds into cd */ ((CDataObject_own_structptr *)cd)->structobj = (PyObject *)cds; assert(explicitlength < 0); cds->c_data = cd->c_data = ((char *)cds) + dataoffset; } else { cd = allocate_owning_object(dataoffset + datasize, ct); if (cd == NULL) return NULL; cd->c_data = ((char *)cd) + dataoffset; if (explicitlength >= 0) ((CDataObject_own_length*)cd)->length = explicitlength; } memset(cd->c_data, 0, datasize); if (init != Py_None) { if (convert_from_object(cd->c_data, (ct->ct_flags & CT_POINTER) ? ct->ct_itemdescr : ct, init) < 0) { Py_DECREF(cd); return NULL; } } return (PyObject *)cd; } static int _my_PyObject_AsBool(PyObject *ob) { /* convert and cast a Python object to a boolean. Accept an integer or a float object, up to a CData 'long double'. */ PyObject *io; PyNumberMethods *nb; int res; #if PY_MAJOR_VERSION < 3 if (PyInt_Check(ob)) { return PyInt_AS_LONG(ob) != 0; } else #endif if (PyLong_Check(ob)) { return _PyLong_Sign(ob) != 0; } else if (PyFloat_Check(ob)) { return PyFloat_AS_DOUBLE(ob) != 0.0; } else if (CData_Check(ob)) { CDataObject *cd = (CDataObject *)ob; if (cd->c_type->ct_flags & CT_PRIMITIVE_FLOAT) { /*READ(cd->c_data, cd->c_type->ct_size)*/ if (cd->c_type->ct_flags & CT_IS_LONGDOUBLE) { /* 'long double' objects: return the answer directly */ return read_raw_longdouble_data(cd->c_data) != 0.0; } else { /* 'float'/'double' objects: return the answer directly */ return read_raw_float_data(cd->c_data, cd->c_type->ct_size) != 0.0; } } } nb = ob->ob_type->tp_as_number; if (nb == NULL || (nb->nb_float == NULL && nb->nb_int == NULL)) { PyErr_SetString(PyExc_TypeError, "integer/float expected"); return -1; } if (nb->nb_float && !CData_Check(ob)) io = (*nb->nb_float) (ob); else io = (*nb->nb_int) (ob); if (io == NULL) return -1; if (PyIntOrLong_Check(io) || PyFloat_Check(io)) { res = _my_PyObject_AsBool(io); } else { PyErr_SetString(PyExc_TypeError, "integer/float conversion failed"); res = -1; } Py_DECREF(io); return res; } static CDataObject *_new_casted_primitive(CTypeDescrObject *ct) { int dataoffset = offsetof(CDataObject_casted_primitive, alignment); CDataObject *cd = (CDataObject *)PyObject_Malloc(dataoffset + ct->ct_size); if (PyObject_Init((PyObject *)cd, &CData_Type) == NULL) return NULL; Py_INCREF(ct); cd->c_type = ct; cd->c_data = ((char*)cd) + dataoffset; cd->c_weakreflist = NULL; return cd; } static CDataObject *cast_to_integer_or_char(CTypeDescrObject *ct, PyObject *ob) { unsigned PY_LONG_LONG value; CDataObject *cd; if (CData_Check(ob) && ((CDataObject *)ob)->c_type->ct_flags & (CT_POINTER|CT_FUNCTIONPTR|CT_ARRAY)) { value = (Py_intptr_t)((CDataObject *)ob)->c_data; } #if PY_MAJOR_VERSION < 3 else if (PyString_Check(ob)) { if (PyString_GET_SIZE(ob) != 1) { PyErr_Format(PyExc_TypeError, "cannot cast string of length %zd to ctype '%s'", PyString_GET_SIZE(ob), ct->ct_name); return NULL; } value = (unsigned char)PyString_AS_STRING(ob)[0]; } #endif #ifdef HAVE_WCHAR_H else if (PyUnicode_Check(ob)) { wchar_t ordinal; if (_my_PyUnicode_AsSingleWideChar(ob, &ordinal) < 0) { PyErr_Format(PyExc_TypeError, "cannot cast unicode string of length %zd to ctype '%s'", PyUnicode_GET_SIZE(ob), ct->ct_name); return NULL; } value = (long)ordinal; } #endif else if (PyBytes_Check(ob)) { int res = _convert_to_char(ob); if (res < 0) return NULL; value = (unsigned char)res; } else if (ct->ct_flags & CT_IS_BOOL) { int res = _my_PyObject_AsBool(ob); if (res < 0) return NULL; value = res; } else { value = _my_PyLong_AsUnsignedLongLong(ob, 0); if (value == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred()) return NULL; } if (ct->ct_flags & CT_IS_BOOL) value = !!value; cd = _new_casted_primitive(ct); if (cd != NULL) write_raw_integer_data(cd->c_data, value, ct->ct_size); return cd; } static PyObject *b_cast(PyObject *self, PyObject *args) { CTypeDescrObject *ct; CDataObject *cd; PyObject *ob; if (!PyArg_ParseTuple(args, "O!O:cast", &CTypeDescr_Type, &ct, &ob)) return NULL; if (ct->ct_flags & (CT_POINTER|CT_FUNCTIONPTR|CT_ARRAY) && ct->ct_size >= 0) { /* cast to a pointer, to a funcptr, or to an array. Note that casting to an array is an extension to the C language, which seems to be necessary in order to sanely get a at some address. */ unsigned PY_LONG_LONG value; if (CData_Check(ob)) { CDataObject *cdsrc = (CDataObject *)ob; if (cdsrc->c_type->ct_flags & (CT_POINTER|CT_FUNCTIONPTR|CT_ARRAY)) { return new_simple_cdata(cdsrc->c_data, ct); } } if ((ct->ct_flags & CT_POINTER) && (ct->ct_itemdescr->ct_flags & CT_IS_FILE) && PyFile_Check(ob)) { FILE *f = PyFile_AsFile(ob); if (f == NULL && PyErr_Occurred()) return NULL; return new_simple_cdata((char *)f, ct); } value = _my_PyLong_AsUnsignedLongLong(ob, 0); if (value == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred()) return NULL; return new_simple_cdata((char *)(Py_intptr_t)value, ct); } else if (ct->ct_flags & (CT_PRIMITIVE_SIGNED|CT_PRIMITIVE_UNSIGNED |CT_PRIMITIVE_CHAR)) { /* cast to an integer type or a char */ return (PyObject *)cast_to_integer_or_char(ct, ob); } else if (ct->ct_flags & CT_PRIMITIVE_FLOAT) { /* cast to a float */ double value; PyObject *io; if (CData_Check(ob)) { CDataObject *cdsrc = (CDataObject *)ob; if (!(cdsrc->c_type->ct_flags & CT_PRIMITIVE_ANY)) goto cannot_cast; io = convert_to_object(cdsrc->c_data, cdsrc->c_type); if (io == NULL) return NULL; } else { io = ob; Py_INCREF(io); } if (PyBytes_Check(io)) { if (PyBytes_GET_SIZE(io) != 1) { Py_DECREF(io); goto cannot_cast; } value = (unsigned char)PyBytes_AS_STRING(io)[0]; } #if HAVE_WCHAR_H else if (PyUnicode_Check(io)) { wchar_t ordinal; if (_my_PyUnicode_AsSingleWideChar(io, &ordinal) < 0) { Py_DECREF(io); goto cannot_cast; } value = (long)ordinal; } #endif else if ((ct->ct_flags & CT_IS_LONGDOUBLE) && CData_Check(io) && (((CDataObject *)io)->c_type->ct_flags & CT_IS_LONGDOUBLE)) { long double lvalue; char *data = ((CDataObject *)io)->c_data; /*READ(data, sizeof(long double)*/ lvalue = read_raw_longdouble_data(data); Py_DECREF(io); cd = _new_casted_primitive(ct); if (cd != NULL) write_raw_longdouble_data(cd->c_data, lvalue); return (PyObject *)cd; } else { value = PyFloat_AsDouble(io); } Py_DECREF(io); if (value == -1.0 && PyErr_Occurred()) return NULL; cd = _new_casted_primitive(ct); if (cd != NULL) { if (!(ct->ct_flags & CT_IS_LONGDOUBLE)) write_raw_float_data(cd->c_data, value, ct->ct_size); else write_raw_longdouble_data(cd->c_data, (long double)value); } return (PyObject *)cd; } else { PyErr_Format(PyExc_TypeError, "cannot cast to ctype '%s'", ct->ct_name); return NULL; } cannot_cast: if (CData_Check(ob)) PyErr_Format(PyExc_TypeError, "cannot cast ctype '%s' to ctype '%s'", ((CDataObject *)ob)->c_type->ct_name, ct->ct_name); else PyErr_Format(PyExc_TypeError, "cannot cast %.200s object to ctype '%s'", Py_TYPE(ob)->tp_name, ct->ct_name); return NULL; } /************************************************************/ typedef struct { PyObject_HEAD void *dl_handle; char *dl_name; } DynLibObject; static void dl_dealloc(DynLibObject *dlobj) { dlclose(dlobj->dl_handle); free(dlobj->dl_name); PyObject_Del(dlobj); } static PyObject *dl_repr(DynLibObject *dlobj) { return PyText_FromFormat("", dlobj->dl_name); } static PyObject *dl_load_function(DynLibObject *dlobj, PyObject *args) { CTypeDescrObject *ct; char *funcname; void *funcptr; int ok; if (!PyArg_ParseTuple(args, "O!s:load_function", &CTypeDescr_Type, &ct, &funcname)) return NULL; ok = 0; if (ct->ct_flags & CT_FUNCTIONPTR) ok = 1; if ((ct->ct_flags & CT_POINTER) && (ct->ct_itemdescr->ct_flags & CT_VOID)) ok = 1; if (!ok) { PyErr_Format(PyExc_TypeError, "function cdata expected, got '%s'", ct->ct_name); return NULL; } dlerror(); /* clear error condition */ funcptr = dlsym(dlobj->dl_handle, funcname); if (funcptr == NULL) { const char *error = dlerror(); PyErr_Format(PyExc_KeyError, "function '%s' not found in library '%s': %s", funcname, dlobj->dl_name, error); return NULL; } return new_simple_cdata(funcptr, ct); } static PyObject *dl_read_variable(DynLibObject *dlobj, PyObject *args) { CTypeDescrObject *ct; char *varname; char *data; if (!PyArg_ParseTuple(args, "O!s:read_variable", &CTypeDescr_Type, &ct, &varname)) return NULL; dlerror(); /* clear error condition */ data = dlsym(dlobj->dl_handle, varname); if (data == NULL) { const char *error = dlerror(); if (error != NULL) { PyErr_Format(PyExc_KeyError, "variable '%s' not found in library '%s': %s", varname, dlobj->dl_name, error); return NULL; } } return convert_to_object(data, ct); } static PyObject *dl_write_variable(DynLibObject *dlobj, PyObject *args) { CTypeDescrObject *ct; PyObject *value; char *varname; char *data; if (!PyArg_ParseTuple(args, "O!sO:write_variable", &CTypeDescr_Type, &ct, &varname, &value)) return NULL; dlerror(); /* clear error condition */ data = dlsym(dlobj->dl_handle, varname); if (data == NULL) { const char *error = dlerror(); PyErr_Format(PyExc_KeyError, "variable '%s' not found in library '%s': %s", varname, dlobj->dl_name, error); return NULL; } if (convert_from_object(data, ct, value) < 0) return NULL; Py_INCREF(Py_None); return Py_None; } static PyMethodDef dl_methods[] = { {"load_function", (PyCFunction)dl_load_function, METH_VARARGS}, {"read_variable", (PyCFunction)dl_read_variable, METH_VARARGS}, {"write_variable", (PyCFunction)dl_write_variable, METH_VARARGS}, {NULL, NULL} /* sentinel */ }; static PyTypeObject dl_type = { PyVarObject_HEAD_INIT(NULL, 0) "_cffi_backend.Library", /* tp_name */ sizeof(DynLibObject), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor)dl_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ (reprfunc)dl_repr, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ 0, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ dl_methods, /* tp_methods */ }; static PyObject *b_load_library(PyObject *self, PyObject *args) { char *filename_or_null, *printable_filename; void *handle; DynLibObject *dlobj; int flags = 0; if (PyTuple_GET_SIZE(args) == 0 || PyTuple_GET_ITEM(args, 0) == Py_None) { PyObject *dummy; if (!PyArg_ParseTuple(args, "|Oi:load_library", &dummy, &flags)) return NULL; filename_or_null = NULL; } else if (!PyArg_ParseTuple(args, "et|i:load_library", Py_FileSystemDefaultEncoding, &filename_or_null, &flags)) return NULL; if ((flags & (RTLD_NOW | RTLD_LAZY)) == 0) flags |= RTLD_NOW; printable_filename = filename_or_null ? filename_or_null : ""; handle = dlopen(filename_or_null, flags); if (handle == NULL) { const char *error = dlerror(); PyErr_Format(PyExc_OSError, "cannot load library %s: %s", printable_filename, error); return NULL; } dlobj = PyObject_New(DynLibObject, &dl_type); if (dlobj == NULL) { dlclose(handle); return NULL; } dlobj->dl_handle = handle; dlobj->dl_name = strdup(printable_filename); return (PyObject *)dlobj; } /************************************************************/ static PyObject *b_new_primitive_type(PyObject *self, PyObject *args) { #define ENUM_PRIMITIVE_TYPES \ EPTYPE(c, char, CT_PRIMITIVE_CHAR) \ EPTYPE(s, short, CT_PRIMITIVE_SIGNED ) \ EPTYPE(i, int, CT_PRIMITIVE_SIGNED ) \ EPTYPE(l, long, CT_PRIMITIVE_SIGNED ) \ EPTYPE(ll, long long, CT_PRIMITIVE_SIGNED ) \ EPTYPE(sc, signed char, CT_PRIMITIVE_SIGNED ) \ EPTYPE(uc, unsigned char, CT_PRIMITIVE_UNSIGNED ) \ EPTYPE(us, unsigned short, CT_PRIMITIVE_UNSIGNED ) \ EPTYPE(ui, unsigned int, CT_PRIMITIVE_UNSIGNED ) \ EPTYPE(ul, unsigned long, CT_PRIMITIVE_UNSIGNED ) \ EPTYPE(ull, unsigned long long, CT_PRIMITIVE_UNSIGNED ) \ EPTYPE(f, float, CT_PRIMITIVE_FLOAT ) \ EPTYPE(d, double, CT_PRIMITIVE_FLOAT ) \ EPTYPE(ld, long double, CT_PRIMITIVE_FLOAT | CT_IS_LONGDOUBLE ) \ ENUM_PRIMITIVE_TYPES_WCHAR \ EPTYPE(b, _Bool, CT_PRIMITIVE_UNSIGNED | CT_IS_BOOL ) \ /* the following types are not primitive in the C sense */ \ EPTYPE(i8, int8_t, CT_PRIMITIVE_SIGNED) \ EPTYPE(u8, uint8_t, CT_PRIMITIVE_UNSIGNED) \ EPTYPE(i16, int16_t, CT_PRIMITIVE_SIGNED) \ EPTYPE(u16, uint16_t, CT_PRIMITIVE_UNSIGNED) \ EPTYPE(i32, int32_t, CT_PRIMITIVE_SIGNED) \ EPTYPE(u32, uint32_t, CT_PRIMITIVE_UNSIGNED) \ EPTYPE(i64, int64_t, CT_PRIMITIVE_SIGNED) \ EPTYPE(u64, uint64_t, CT_PRIMITIVE_UNSIGNED) \ EPTYPE(il8, int_least8_t, CT_PRIMITIVE_SIGNED) \ EPTYPE(ul8, uint_least8_t, CT_PRIMITIVE_UNSIGNED) \ EPTYPE(il16, int_least16_t, CT_PRIMITIVE_SIGNED) \ EPTYPE(ul16, uint_least16_t, CT_PRIMITIVE_UNSIGNED) \ EPTYPE(il32, int_least32_t, CT_PRIMITIVE_SIGNED) \ EPTYPE(ul32, uint_least32_t, CT_PRIMITIVE_UNSIGNED) \ EPTYPE(il64, int_least64_t, CT_PRIMITIVE_SIGNED) \ EPTYPE(ul64, uint_least64_t, CT_PRIMITIVE_UNSIGNED) \ EPTYPE(if8, int_fast8_t, CT_PRIMITIVE_SIGNED) \ EPTYPE(uf8, uint_fast8_t, CT_PRIMITIVE_UNSIGNED) \ EPTYPE(if16, int_fast16_t, CT_PRIMITIVE_SIGNED) \ EPTYPE(uf16, uint_fast16_t, CT_PRIMITIVE_UNSIGNED) \ EPTYPE(if32, int_fast32_t, CT_PRIMITIVE_SIGNED) \ EPTYPE(uf32, uint_fast32_t, CT_PRIMITIVE_UNSIGNED) \ EPTYPE(if64, int_fast64_t, CT_PRIMITIVE_SIGNED) \ EPTYPE(uf64, uint_fast64_t, CT_PRIMITIVE_UNSIGNED) \ EPTYPE(ip, intptr_t, CT_PRIMITIVE_SIGNED) \ EPTYPE(up, uintptr_t, CT_PRIMITIVE_UNSIGNED) \ EPTYPE(im, intmax_t, CT_PRIMITIVE_SIGNED) \ EPTYPE(um, uintmax_t, CT_PRIMITIVE_UNSIGNED) \ EPTYPE(pd, ptrdiff_t, CT_PRIMITIVE_SIGNED) \ EPTYPE(sz, size_t, CT_PRIMITIVE_UNSIGNED) \ EPTYPE(ssz, ssize_t, CT_PRIMITIVE_SIGNED) #ifdef HAVE_WCHAR_H # define ENUM_PRIMITIVE_TYPES_WCHAR \ EPTYPE(wc, wchar_t, CT_PRIMITIVE_CHAR ) #else # define ENUM_PRIMITIVE_TYPES_WCHAR /* nothing */ #endif #define EPTYPE(code, typename, flags) \ struct aligncheck_##code { char x; typename y; }; ENUM_PRIMITIVE_TYPES #undef EPTYPE CTypeDescrObject *td; const char *name; static const struct descr_s { const char *name; int size, align, flags; } types[] = { #define EPTYPE(code, typename, flags) \ { #typename, \ sizeof(typename), \ offsetof(struct aligncheck_##code, y), \ flags \ }, ENUM_PRIMITIVE_TYPES #undef EPTYPE #undef ENUM_PRIMITIVE_TYPES_WCHAR #undef ENUM_PRIMITIVE_TYPES { NULL } }; const struct descr_s *ptypes; int name_size; ffi_type *ffitype; if (!PyArg_ParseTuple(args, "s:new_primitive_type", &name)) return NULL; for (ptypes=types; ; ptypes++) { if (ptypes->name == NULL) { #ifndef HAVE_WCHAR_H if (strcmp(name, "wchar_t")) PyErr_SetString(PyExc_NotImplementedError, name); else #endif PyErr_SetString(PyExc_KeyError, name); return NULL; } if (strcmp(name, ptypes->name) == 0) break; } if (ptypes->flags & CT_PRIMITIVE_SIGNED) { switch (ptypes->size) { case 1: ffitype = &ffi_type_sint8; break; case 2: ffitype = &ffi_type_sint16; break; case 4: ffitype = &ffi_type_sint32; break; case 8: ffitype = &ffi_type_sint64; break; default: goto bad_ffi_type; } } else if (ptypes->flags & CT_PRIMITIVE_FLOAT) { if (strcmp(ptypes->name, "float") == 0) ffitype = &ffi_type_float; else if (strcmp(ptypes->name, "double") == 0) ffitype = &ffi_type_double; else if (strcmp(ptypes->name, "long double") == 0) ffitype = &ffi_type_longdouble; else goto bad_ffi_type; } else { switch (ptypes->size) { case 1: ffitype = &ffi_type_uint8; break; case 2: ffitype = &ffi_type_uint16; break; case 4: ffitype = &ffi_type_uint32; break; case 8: ffitype = &ffi_type_uint64; break; default: goto bad_ffi_type; } } name_size = strlen(ptypes->name) + 1; td = ctypedescr_new(name_size); if (td == NULL) return NULL; memcpy(td->ct_name, name, name_size); td->ct_size = ptypes->size; td->ct_length = ptypes->align; td->ct_extra = ffitype; td->ct_flags = ptypes->flags; if (td->ct_flags & (CT_PRIMITIVE_SIGNED | CT_PRIMITIVE_CHAR)) { if (td->ct_size <= sizeof(long)) td->ct_flags |= CT_PRIMITIVE_FITS_LONG; } else if (td->ct_flags & CT_PRIMITIVE_UNSIGNED) { if (td->ct_size < sizeof(long)) td->ct_flags |= CT_PRIMITIVE_FITS_LONG; } td->ct_name_position = strlen(td->ct_name); return (PyObject *)td; bad_ffi_type: PyErr_Format(PyExc_NotImplementedError, "primitive type '%s' has size %d; " "the supported sizes are 1, 2, 4, 8", name, (int)ptypes->size); return NULL; } static PyObject *b_new_pointer_type(PyObject *self, PyObject *args) { CTypeDescrObject *td, *ctitem; const char *extra; if (!PyArg_ParseTuple(args, "O!:new_pointer_type", &CTypeDescr_Type, &ctitem)) return NULL; if (ctitem->ct_flags & CT_ARRAY) extra = "(*)"; /* obscure case: see test_array_add */ else extra = " *"; td = ctypedescr_new_on_top(ctitem, extra, 2); if (td == NULL) return NULL; td->ct_size = sizeof(void *); td->ct_length = -1; td->ct_flags = CT_POINTER; if (ctitem->ct_flags & (CT_STRUCT|CT_UNION)) td->ct_flags |= CT_IS_PTR_TO_OWNED; if (ctitem->ct_flags & CT_VOID) td->ct_flags |= CT_IS_VOID_PTR; if ((ctitem->ct_flags & CT_VOID) || ((ctitem->ct_flags & CT_PRIMITIVE_CHAR) && ctitem->ct_size == sizeof(char))) td->ct_flags |= CT_CAST_ANYTHING; /* 'void *' or 'char *' only */ return (PyObject *)td; } static PyObject *b_new_array_type(PyObject *self, PyObject *args) { PyObject *lengthobj; CTypeDescrObject *ctptr; if (!PyArg_ParseTuple(args, "O!O:new_array_type", &CTypeDescr_Type, &ctptr, &lengthobj)) return NULL; return new_array_type(ctptr, lengthobj); } static PyObject * new_array_type(CTypeDescrObject *ctptr, PyObject *lengthobj) { CTypeDescrObject *td, *ctitem; char extra_text[32]; Py_ssize_t length, arraysize; if (!(ctptr->ct_flags & CT_POINTER)) { PyErr_SetString(PyExc_TypeError, "first arg must be a pointer ctype"); return NULL; } ctitem = ctptr->ct_itemdescr; if (ctitem->ct_size < 0) { PyErr_Format(PyExc_ValueError, "array item of unknown size: '%s'", ctitem->ct_name); return NULL; } if (lengthobj == Py_None) { sprintf(extra_text, "[]"); length = -1; arraysize = -1; } else { length = PyNumber_AsSsize_t(lengthobj, PyExc_OverflowError); if (length < 0) { if (!PyErr_Occurred()) PyErr_SetString(PyExc_ValueError, "negative array length"); return NULL; } sprintf(extra_text, "[%llu]", (unsigned PY_LONG_LONG)length); arraysize = length * ctitem->ct_size; if (length > 0 && (arraysize / length) != ctitem->ct_size) { PyErr_SetString(PyExc_OverflowError, "array size would overflow a Py_ssize_t"); return NULL; } } td = ctypedescr_new_on_top(ctitem, extra_text, 0); if (td == NULL) return NULL; Py_INCREF(ctptr); td->ct_stuff = (PyObject *)ctptr; td->ct_size = arraysize; td->ct_length = length; td->ct_flags = CT_ARRAY; return (PyObject *)td; } static PyObject *b_new_void_type(PyObject *self, PyObject *args) { int name_size = strlen("void") + 1; CTypeDescrObject *td = ctypedescr_new(name_size); if (td == NULL) return NULL; memcpy(td->ct_name, "void", name_size); td->ct_size = -1; td->ct_flags = CT_VOID | CT_IS_OPAQUE; td->ct_name_position = strlen("void"); return (PyObject *)td; } static PyObject *_b_struct_or_union_type(const char *name, int flag) { int namelen = strlen(name); CTypeDescrObject *td = ctypedescr_new(namelen + 1); if (td == NULL) return NULL; td->ct_size = -1; td->ct_length = -1; td->ct_flags = flag | CT_IS_OPAQUE; memcpy(td->ct_name, name, namelen + 1); td->ct_name_position = namelen; return (PyObject *)td; } static PyObject *b_new_struct_type(PyObject *self, PyObject *args) { char *name; int flag; if (!PyArg_ParseTuple(args, "s:new_struct_type", &name)) return NULL; flag = CT_STRUCT; if (strcmp(name, "struct _IO_FILE") == 0 || strcmp(name, "FILE") == 0) flag |= CT_IS_FILE; return _b_struct_or_union_type(name, flag); } static PyObject *b_new_union_type(PyObject *self, PyObject *args) { char *name; if (!PyArg_ParseTuple(args, "s:new_union_type", &name)) return NULL; return _b_struct_or_union_type(name, CT_UNION); } static CFieldObject * _add_field(PyObject *interned_fields, PyObject *fname, CTypeDescrObject *ftype, Py_ssize_t offset, int bitshift, int fbitsize) { int err; Py_ssize_t prev_size; CFieldObject *cf = PyObject_New(CFieldObject, &CField_Type); if (cf == NULL) return NULL; Py_INCREF(ftype); cf->cf_type = ftype; cf->cf_offset = offset; cf->cf_bitshift = bitshift; cf->cf_bitsize = fbitsize; Py_INCREF(fname); PyText_InternInPlace(&fname); prev_size = PyDict_Size(interned_fields); err = PyDict_SetItem(interned_fields, fname, (PyObject *)cf); Py_DECREF(fname); Py_DECREF(cf); if (err < 0) return NULL; if (PyDict_Size(interned_fields) != prev_size + 1) { PyErr_Format(PyExc_KeyError, "duplicate field name '%s'", PyText_AS_UTF8(fname)); return NULL; } return cf; /* borrowed reference */ } #define SF_MSVC_BITFIELDS 0x01 #define SF_GCC_ARM_BITFIELDS 0x02 #define SF_GCC_X86_BITFIELDS 0x10 #define SF_GCC_BIG_ENDIAN 0x04 #define SF_GCC_LITTLE_ENDIAN 0x40 #define SF_PACKED 0x08 static int complete_sflags(int sflags) { /* add one of the SF_xxx_BITFIELDS flags if none is specified */ if (!(sflags & (SF_MSVC_BITFIELDS | SF_GCC_ARM_BITFIELDS | SF_GCC_X86_BITFIELDS))) { #ifdef MS_WIN32 sflags |= SF_MSVC_BITFIELDS; #else # if defined(__arm__) || defined(__aarch64__) sflags |= SF_GCC_ARM_BITFIELDS; # else sflags |= SF_GCC_X86_BITFIELDS; # endif #endif } /* add one of SF_GCC_xx_ENDIAN if none is specified */ if (!(sflags & (SF_GCC_BIG_ENDIAN | SF_GCC_LITTLE_ENDIAN))) { int _check_endian = 1; if (*(char *)&_check_endian == 0) sflags |= SF_GCC_BIG_ENDIAN; else sflags |= SF_GCC_LITTLE_ENDIAN; } return sflags; } static PyObject *b_complete_struct_or_union(PyObject *self, PyObject *args) { CTypeDescrObject *ct; PyObject *fields, *interned_fields, *ignored; int is_union, alignment; Py_ssize_t boffset, i, nb_fields, boffsetmax; Py_ssize_t totalsize = -1; int totalalignment = -1; CFieldObject **previous; int prev_bitfield_size, prev_bitfield_free; int sflags = 0; if (!PyArg_ParseTuple(args, "O!O!|Onii:complete_struct_or_union", &CTypeDescr_Type, &ct, &PyList_Type, &fields, &ignored, &totalsize, &totalalignment, &sflags)) return NULL; sflags = complete_sflags(sflags); if ((ct->ct_flags & (CT_STRUCT|CT_IS_OPAQUE)) == (CT_STRUCT|CT_IS_OPAQUE)) { is_union = 0; } else if ((ct->ct_flags & (CT_UNION|CT_IS_OPAQUE)) == (CT_UNION|CT_IS_OPAQUE)) { is_union = 1; } else { PyErr_SetString(PyExc_TypeError, "first arg must be a non-initialized struct or union ctype"); return NULL; } alignment = 1; boffset = 0; /* this number is in *bits*, not bytes! */ boffsetmax = 0; /* the maximum value of boffset, in bits too */ prev_bitfield_size = 0; prev_bitfield_free = 0; nb_fields = PyList_GET_SIZE(fields); interned_fields = PyDict_New(); if (interned_fields == NULL) return NULL; previous = (CFieldObject **)&ct->ct_extra; for (i=0; ict_size < 0) { if ((ftype->ct_flags & CT_ARRAY) && fbitsize < 0 && (i == nb_fields - 1 || foffset != -1)) { ct->ct_flags |= CT_WITH_VAR_ARRAY; } else { PyErr_Format(PyExc_TypeError, "field '%s.%s' has ctype '%s' of unknown size", ct->ct_name, PyText_AS_UTF8(fname), ftype->ct_name); goto error; } } if (is_union) boffset = 0; /* reset each field at offset 0 */ /* update the total alignment requirement, but skip it if the field is an anonymous bitfield or if SF_PACKED */ falign = (sflags & SF_PACKED) ? 1 : get_alignment(ftype); if (falign < 0) goto error; do_align = 1; if (!(sflags & SF_GCC_ARM_BITFIELDS) && fbitsize >= 0) { if (!(sflags & SF_MSVC_BITFIELDS)) { /* GCC: anonymous bitfields (of any size) don't cause alignment */ do_align = PyText_GetSize(fname) > 0; } else { /* MSVC: zero-sized bitfields don't cause alignment */ do_align = fbitsize > 0; } } if (alignment < falign && do_align) alignment = falign; if (fbitsize < 0) { /* not a bitfield: common case */ int bs_flag; if (ftype->ct_flags & CT_ARRAY && ftype->ct_length == 0) bs_flag = BS_EMPTY_ARRAY; else bs_flag = BS_REGULAR; /* align this field to its own 'falign' by inserting padding */ boffset = (boffset + falign*8-1) & ~(falign*8-1); /* bits! */ if (foffset >= 0) { /* a forced field position: ignore the offset just computed, except to know if we must set CT_CUSTOM_FIELD_POS */ if (boffset != foffset * 8) ct->ct_flags |= CT_CUSTOM_FIELD_POS; boffset = foffset * 8; } if (PyText_GetSize(fname) == 0 && ftype->ct_flags & (CT_STRUCT|CT_UNION)) { /* a nested anonymous struct or union */ CFieldObject *cfsrc = (CFieldObject *)ftype->ct_extra; for (; cfsrc != NULL; cfsrc = cfsrc->cf_next) { /* broken complexity in the call to get_field_name(), but we'll assume you never do that with nested anonymous structures with thousand of fields */ *previous = _add_field(interned_fields, get_field_name(ftype, cfsrc), cfsrc->cf_type, boffset / 8 + cfsrc->cf_offset, cfsrc->cf_bitshift, cfsrc->cf_bitsize); if (*previous == NULL) goto error; previous = &(*previous)->cf_next; } /* always forbid such structures from being passed by value */ ct->ct_flags |= CT_CUSTOM_FIELD_POS; } else { *previous = _add_field(interned_fields, fname, ftype, boffset / 8, bs_flag, -1); if (*previous == NULL) goto error; previous = &(*previous)->cf_next; } if (ftype->ct_size >= 0) boffset += ftype->ct_size * 8; prev_bitfield_size = 0; } else { /* this is the case of a bitfield */ Py_ssize_t field_offset_bytes; int bits_already_occupied, bitshift; if (foffset >= 0) { PyErr_Format(PyExc_TypeError, "field '%s.%s' is a bitfield, " "but a fixed offset is specified", ct->ct_name, PyText_AS_UTF8(fname)); goto error; } if (!(ftype->ct_flags & (CT_PRIMITIVE_SIGNED | CT_PRIMITIVE_UNSIGNED | CT_PRIMITIVE_CHAR))) { PyErr_Format(PyExc_TypeError, "field '%s.%s' declared as '%s' cannot be a bit field", ct->ct_name, PyText_AS_UTF8(fname), ftype->ct_name); goto error; } if (fbitsize > 8 * ftype->ct_size) { PyErr_Format(PyExc_TypeError, "bit field '%s.%s' is declared '%s:%d', which " "exceeds the width of the type", ct->ct_name, PyText_AS_UTF8(fname), ftype->ct_name, fbitsize); goto error; } /* compute the starting position of the theoretical field that covers a complete 'ftype', inside of which we will locate the real bitfield */ field_offset_bytes = boffset / 8; field_offset_bytes &= ~(falign - 1); if (fbitsize == 0) { if (PyText_GetSize(fname) > 0) { PyErr_Format(PyExc_TypeError, "field '%s.%s' is declared with :0", ct->ct_name, PyText_AS_UTF8(fname)); goto error; } if (!(sflags & SF_MSVC_BITFIELDS)) { /* GCC's notion of "ftype :0;" */ /* pad boffset to a value aligned for "ftype" */ if (boffset > field_offset_bytes * 8) { field_offset_bytes += falign; assert(boffset < field_offset_bytes * 8); } boffset = field_offset_bytes * 8; } else { /* MSVC's notion of "ftype :0;" */ /* Mostly ignored. It seems they only serve as separator between other bitfields, to force them into separate words. */ } prev_bitfield_size = 0; } else { if (!(sflags & SF_MSVC_BITFIELDS)) { /* GCC's algorithm */ /* Can the field start at the offset given by 'boffset'? It can if it would entirely fit into an aligned ftype field. */ bits_already_occupied = boffset - (field_offset_bytes * 8); if (bits_already_occupied + fbitsize > 8 * ftype->ct_size) { /* it would not fit, we need to start at the next allowed position */ if ((sflags & SF_PACKED) && (bits_already_occupied & 7)) { PyErr_Format(PyExc_NotImplementedError, "with 'packed', gcc would compile field " "'%s.%s' to reuse some bits in the previous " "field", ct->ct_name, PyText_AS_UTF8(fname)); goto error; } field_offset_bytes += falign; assert(boffset < field_offset_bytes * 8); boffset = field_offset_bytes * 8; bitshift = 0; } else { bitshift = bits_already_occupied; assert(bitshift >= 0); } boffset += fbitsize; } else { /* MSVC's algorithm */ /* A bitfield is considered as taking the full width of their declared type. It can share some bits with the previous field only if it was also a bitfield and used a type of the same size. */ if (prev_bitfield_size == ftype->ct_size && prev_bitfield_free >= fbitsize) { /* yes: reuse */ bitshift = 8 * prev_bitfield_size - prev_bitfield_free; } else { /* no: start a new full field */ boffset = (boffset + falign*8-1) & ~(falign*8-1); /*align*/ boffset += ftype->ct_size * 8; bitshift = 0; prev_bitfield_size = ftype->ct_size; prev_bitfield_free = 8 * prev_bitfield_size; } prev_bitfield_free -= fbitsize; field_offset_bytes = boffset / 8 - ftype->ct_size; } if (sflags & SF_GCC_BIG_ENDIAN) bitshift = 8 * ftype->ct_size - fbitsize - bitshift; *previous = _add_field(interned_fields, fname, ftype, field_offset_bytes, bitshift, fbitsize); if (*previous == NULL) goto error; previous = &(*previous)->cf_next; } } if (boffset > boffsetmax) boffsetmax = boffset; } *previous = NULL; /* Like C, if the size of this structure would be zero, we compute it as 1 instead. But for ctypes support, we allow the manually- specified totalsize to be zero in this case. */ boffsetmax = (boffsetmax + 7) / 8; /* bits -> bytes */ if (totalsize < 0) { totalsize = (boffsetmax + alignment - 1) & ~(alignment-1); if (totalsize == 0) totalsize = 1; } else if (totalsize < boffsetmax) { PyErr_Format(PyExc_TypeError, "%s cannot be of size %zd: there are fields at least " "up to %zd", ct->ct_name, totalsize, boffsetmax); goto error; } ct->ct_size = totalsize; ct->ct_length = totalalignment < 0 ? alignment : totalalignment; ct->ct_stuff = interned_fields; ct->ct_flags &= ~CT_IS_OPAQUE; Py_INCREF(Py_None); return Py_None; error: Py_DECREF(interned_fields); return NULL; } struct funcbuilder_s { Py_ssize_t nb_bytes; char *bufferp; ffi_type **atypes; ffi_type *rtype; Py_ssize_t nargs; CTypeDescrObject *fct; }; static void *fb_alloc(struct funcbuilder_s *fb, Py_ssize_t size) { if (fb->bufferp == NULL) { fb->nb_bytes += size; return NULL; } else { char *result = fb->bufferp; fb->bufferp += size; return result; } } static ffi_type *fb_fill_type(struct funcbuilder_s *fb, CTypeDescrObject *ct, int is_result_type) { if (ct->ct_flags & CT_PRIMITIVE_ANY) { return (ffi_type *)ct->ct_extra; } else if (ct->ct_flags & (CT_POINTER|CT_FUNCTIONPTR)) { return &ffi_type_pointer; } else if ((ct->ct_flags & CT_VOID) && is_result_type) { return &ffi_type_void; } if (ct->ct_size <= 0) { PyErr_Format(PyExc_TypeError, ct->ct_size < 0 ? "ctype '%s' has incomplete type" : "ctype '%s' has size 0", ct->ct_name); return NULL; } if (ct->ct_flags & CT_STRUCT) { ffi_type *ffistruct, *ffifield; ffi_type **elements; Py_ssize_t i, n, nflat; CFieldObject *cf; /* We can't pass a struct that was completed by verify(). Issue: assume verify() is given "struct { long b; ...; }". Then it will complete it in the same way whether it is actually "struct { long a, b; }" or "struct { double a; long b; }". But on 64-bit UNIX, these two structs are passed by value differently: e.g. on x86-64, "b" ends up in register "rsi" in the first case and "rdi" in the second case. Another reason for CT_CUSTOM_FIELD_POS would be anonymous nested structures: we lost the information about having it here, so better safe (and forbid it) than sorry (and maybe crash). */ if (ct->ct_flags & CT_CUSTOM_FIELD_POS) { PyErr_SetString(PyExc_TypeError, "cannot pass as an argument a struct that was completed " "with verify() (see _cffi_backend.c for details of why)"); return NULL; } n = PyDict_Size(ct->ct_stuff); nflat = 0; /* walk the fields, expanding arrays into repetitions; first, only count how many flattened fields there are */ cf = (CFieldObject *)ct->ct_extra; for (i=0; icf_bitshift >= 0) { PyErr_SetString(PyExc_NotImplementedError, "cannot pass as argument or return value " "a struct with bit fields"); return NULL; } flat = 1; ct = cf->cf_type; while (ct->ct_flags & CT_ARRAY) { flat *= ct->ct_length; ct = ct->ct_itemdescr; } if (flat <= 0) { PyErr_SetString(PyExc_NotImplementedError, "cannot pass as argument or return value " "a struct with a zero-length array"); return NULL; } nflat += flat; cf = cf->cf_next; } assert(cf == NULL); /* next, allocate and fill the flattened list */ elements = fb_alloc(fb, (nflat + 1) * sizeof(ffi_type*)); nflat = 0; cf = (CFieldObject *)ct->ct_extra; for (i=0; icf_type; while (ct->ct_flags & CT_ARRAY) { flat *= ct->ct_length; ct = ct->ct_itemdescr; } ffifield = fb_fill_type(fb, ct, 0); if (elements != NULL) { for (j=0; jcf_next; } /* finally, allocate the FFI_TYPE_STRUCT */ ffistruct = fb_alloc(fb, sizeof(ffi_type)); if (ffistruct != NULL) { elements[nflat] = NULL; ffistruct->size = ct->ct_size; ffistruct->alignment = ct->ct_length; ffistruct->type = FFI_TYPE_STRUCT; ffistruct->elements = elements; } return ffistruct; } else { PyErr_Format(PyExc_NotImplementedError, "ctype '%s' not supported as argument or return value", ct->ct_name); return NULL; } } #define ALIGN_ARG(n) ((n) + 7) & ~7 static int fb_build(struct funcbuilder_s *fb, PyObject *fargs, CTypeDescrObject *fresult) { Py_ssize_t i, nargs = PyTuple_GET_SIZE(fargs); Py_ssize_t exchange_offset; cif_description_t *cif_descr; /* ffi buffer: start with a cif_description */ cif_descr = fb_alloc(fb, sizeof(cif_description_t) + nargs * sizeof(Py_ssize_t)); /* ffi buffer: next comes an array of 'ffi_type*', one per argument */ fb->atypes = fb_alloc(fb, nargs * sizeof(ffi_type*)); fb->nargs = nargs; /* ffi buffer: next comes the result type */ fb->rtype = fb_fill_type(fb, fresult, 1); if (PyErr_Occurred()) return -1; if (cif_descr != NULL) { /* exchange data size */ /* first, enough room for an array of 'nargs' pointers */ exchange_offset = nargs * sizeof(void*); exchange_offset = ALIGN_ARG(exchange_offset); cif_descr->exchange_offset_arg[0] = exchange_offset; /* then enough room for the result --- which means at least sizeof(ffi_arg), according to the ffi docs */ i = fb->rtype->size; if (i < (Py_ssize_t)sizeof(ffi_arg)) i = sizeof(ffi_arg); exchange_offset += i; } else exchange_offset = 0; /* not used */ /* loop over the arguments */ for (i=0; ict_flags & CT_ARRAY) farg = (CTypeDescrObject *)farg->ct_stuff; /* ffi buffer: fill in the ffi for the i'th argument */ assert(farg != NULL); atype = fb_fill_type(fb, farg, 0); if (PyErr_Occurred()) return -1; if (fb->atypes != NULL) { fb->atypes[i] = atype; /* exchange data size */ exchange_offset = ALIGN_ARG(exchange_offset); cif_descr->exchange_offset_arg[1 + i] = exchange_offset; exchange_offset += atype->size; } } if (cif_descr != NULL) { /* exchange data size */ cif_descr->exchange_size = exchange_offset; } return 0; } #undef ALIGN_ARG static void fb_cat_name(struct funcbuilder_s *fb, char *piece, int piecelen) { if (fb->bufferp == NULL) { fb->nb_bytes += piecelen; } else { memcpy(fb->bufferp, piece, piecelen); fb->bufferp += piecelen; } } static int fb_build_name(struct funcbuilder_s *fb, PyObject *fargs, CTypeDescrObject *fresult, int ellipsis) { Py_ssize_t i, nargs = PyTuple_GET_SIZE(fargs); fb->nargs = nargs; /* name: the function type name we build here is, like in C, made as follows: RESULT_TYPE_HEAD (*)(ARG_1_TYPE, ARG_2_TYPE, etc) RESULT_TYPE_TAIL */ fb_cat_name(fb, fresult->ct_name, fresult->ct_name_position); fb_cat_name(fb, "(*)(", 4); if (fb->fct) { i = fresult->ct_name_position + 2; /* between '(*' and ')(' */ fb->fct->ct_name_position = i; } /* loop over the arguments */ for (i=0; i 0) fb_cat_name(fb, ", ", 2); fb_cat_name(fb, farg->ct_name, strlen(farg->ct_name)); } /* name: add the '...' if needed */ if (ellipsis) { if (nargs > 0) fb_cat_name(fb, ", ", 2); fb_cat_name(fb, "...", 3); } /* name: concatenate the tail of the result type */ fb_cat_name(fb, ")", 1); fb_cat_name(fb, fresult->ct_name + fresult->ct_name_position, strlen(fresult->ct_name) - fresult->ct_name_position + 1); return 0; } static CTypeDescrObject *fb_prepare_ctype(struct funcbuilder_s *fb, PyObject *fargs, CTypeDescrObject *fresult, int ellipsis) { CTypeDescrObject *fct; fb->nb_bytes = 0; fb->bufferp = NULL; fb->fct = NULL; /* compute the total size needed for the name */ if (fb_build_name(fb, fargs, fresult, ellipsis) < 0) return NULL; /* allocate the function type */ fct = ctypedescr_new(fb->nb_bytes); if (fct == NULL) return NULL; fb->fct = fct; /* call again fb_build_name() to really build the ct_name */ fb->bufferp = fct->ct_name; if (fb_build_name(fb, fargs, fresult, ellipsis) < 0) goto error; assert(fb->bufferp == fct->ct_name + fb->nb_bytes); fct->ct_extra = NULL; fct->ct_size = sizeof(void(*)(void)); fct->ct_flags = CT_FUNCTIONPTR; return fct; error: Py_DECREF(fct); return NULL; } static cif_description_t *fb_prepare_cif(PyObject *fargs, CTypeDescrObject *fresult, ffi_abi fabi) { char *buffer; cif_description_t *cif_descr; struct funcbuilder_s funcbuffer; funcbuffer.nb_bytes = 0; funcbuffer.bufferp = NULL; /* compute the total size needed in the buffer for libffi */ if (fb_build(&funcbuffer, fargs, fresult) < 0) return NULL; /* allocate the buffer */ buffer = PyObject_Malloc(funcbuffer.nb_bytes); if (buffer == NULL) { PyErr_NoMemory(); return NULL; } /* call again fb_build() to really build the libffi data structures */ funcbuffer.bufferp = buffer; if (fb_build(&funcbuffer, fargs, fresult) < 0) goto error; assert(funcbuffer.bufferp == buffer + funcbuffer.nb_bytes); cif_descr = (cif_description_t *)buffer; if (ffi_prep_cif(&cif_descr->cif, fabi, funcbuffer.nargs, funcbuffer.rtype, funcbuffer.atypes) != FFI_OK) { PyErr_SetString(PyExc_SystemError, "libffi failed to build this function type"); goto error; } return cif_descr; error: PyObject_Free(buffer); return NULL; } static PyObject *b_new_function_type(PyObject *self, PyObject *args) { PyObject *fargs, *fabiobj; CTypeDescrObject *fresult; CTypeDescrObject *fct; int ellipsis = 0, fabi = FFI_DEFAULT_ABI; struct funcbuilder_s funcbuilder; Py_ssize_t i; if (!PyArg_ParseTuple(args, "O!O!|ii:new_function_type", &PyTuple_Type, &fargs, &CTypeDescr_Type, &fresult, &ellipsis, &fabi)) return NULL; if (fresult->ct_flags & CT_UNION) { PyErr_SetString(PyExc_NotImplementedError, "function returning a union"); return NULL; } if ((fresult->ct_size < 0 && !(fresult->ct_flags & CT_VOID)) || (fresult->ct_flags & CT_ARRAY)) { char *msg; if (fresult->ct_flags & CT_IS_OPAQUE) msg = "result type '%s' is opaque"; else msg = "invalid result type: '%s'"; PyErr_Format(PyExc_TypeError, msg, fresult->ct_name); return NULL; } fct = fb_prepare_ctype(&funcbuilder, fargs, fresult, ellipsis); if (fct == NULL) return NULL; if (!ellipsis) { /* Functions with '...' varargs are stored without a cif_descr at all. The cif is computed on every call from the actual types passed in. For all other functions, the cif_descr is computed here. */ cif_description_t *cif_descr; cif_descr = fb_prepare_cif(fargs, fresult, fabi); if (cif_descr == NULL) goto error; fct->ct_extra = (char *)cif_descr; } /* build the signature, given by a tuple of ctype objects */ fct->ct_stuff = PyTuple_New(2 + funcbuilder.nargs); if (fct->ct_stuff == NULL) goto error; fabiobj = PyInt_FromLong(fabi); if (fabiobj == NULL) goto error; PyTuple_SET_ITEM(fct->ct_stuff, 0, fabiobj); Py_INCREF(fresult); PyTuple_SET_ITEM(fct->ct_stuff, 1, (PyObject *)fresult); for (i=0; ict_flags & CT_ARRAY) o = ((CTypeDescrObject *)o)->ct_stuff; Py_INCREF(o); PyTuple_SET_ITEM(fct->ct_stuff, 2 + i, o); } fct->ct_size = sizeof(void(*)(void)); fct->ct_flags = CT_FUNCTIONPTR; return (PyObject *)fct; error: Py_DECREF(fct); return NULL; } static int convert_from_object_fficallback(char *result, CTypeDescrObject *ctype, PyObject *pyobj) { /* work work work around a libffi irregularity: for integer return types we have to fill at least a complete 'ffi_arg'-sized result buffer. */ if (ctype->ct_size < (Py_ssize_t)sizeof(ffi_arg)) { if (ctype->ct_flags & CT_VOID) { if (pyobj == Py_None) { return 0; } else { PyErr_SetString(PyExc_TypeError, "callback with the return type 'void' must return None"); return -1; } } if (ctype->ct_flags & CT_PRIMITIVE_SIGNED) { PY_LONG_LONG value; /* It's probably fine to always zero-extend, but you never know: maybe some code somewhere expects a negative 'short' result to be returned into EAX as a 32-bit negative number. Better safe than sorry. This code is about that case. Let's ignore this for enums. */ /* do a first conversion only to detect overflows. This conversion produces stuff that is otherwise ignored. */ if (convert_from_object(result, ctype, pyobj) < 0) return -1; /* manual inlining and tweaking of convert_from_object() in order to write a whole 'ffi_arg'. */ value = _my_PyLong_AsLongLong(pyobj); if (value == -1 && PyErr_Occurred()) return -1; write_raw_integer_data(result, value, sizeof(ffi_arg)); return 0; } else if (ctype->ct_flags & (CT_PRIMITIVE_CHAR | CT_PRIMITIVE_SIGNED | CT_PRIMITIVE_UNSIGNED)) { /* zero extension: fill the '*result' with zeros, and (on big- endian machines) correct the 'result' pointer to write to */ memset(result, 0, sizeof(ffi_arg)); #ifdef WORDS_BIGENDIAN result += (sizeof(ffi_arg) - ctype->ct_size); #endif } } return convert_from_object(result, ctype, pyobj); } static void _my_PyErr_WriteUnraisable(PyObject *obj, char *extra_error_line) { /* like PyErr_WriteUnraisable(), but write a full traceback */ PyObject *f, *t, *v, *tb; PyErr_Fetch(&t, &v, &tb); #if PY_MAJOR_VERSION >= 3 /* jump through hoops to ensure the tb is attached to v, on Python 3 */ PyErr_NormalizeException(&t, &v, &tb); if (tb == NULL) { tb = Py_None; Py_INCREF(tb); } PyException_SetTraceback(v, tb); #endif f = PySys_GetObject("stderr"); if (f != NULL) { PyFile_WriteString("From callback ", f); PyFile_WriteObject(obj, f, 0); PyFile_WriteString(":\n", f); if (extra_error_line != NULL) PyFile_WriteString(extra_error_line, f); PyErr_Display(t, v, tb); } Py_XDECREF(t); Py_XDECREF(v); Py_XDECREF(tb); } static void invoke_callback(ffi_cif *cif, void *result, void **args, void *userdata) { save_errno(); { #ifdef WITH_THREAD PyGILState_STATE state = PyGILState_Ensure(); #endif PyObject *cb_args = (PyObject *)userdata; CTypeDescrObject *ct = (CTypeDescrObject *)PyTuple_GET_ITEM(cb_args, 0); PyObject *signature = ct->ct_stuff; PyObject *py_ob = PyTuple_GET_ITEM(cb_args, 1); PyObject *py_args = NULL; PyObject *py_res = NULL; PyObject *py_rawerr; Py_ssize_t i, n; char *extra_error_line = NULL; #define SIGNATURE(i) ((CTypeDescrObject *)PyTuple_GET_ITEM(signature, i)) Py_INCREF(cb_args); n = PyTuple_GET_SIZE(signature) - 2; py_args = PyTuple_New(n); if (py_args == NULL) goto error; for (i=0; ict_size > 0) { py_rawerr = PyTuple_GET_ITEM(cb_args, 2); memcpy(result, PyBytes_AS_STRING(py_rawerr), PyBytes_GET_SIZE(py_rawerr)); } goto done; } #undef SIGNATURE } static PyObject *b_callback(PyObject *self, PyObject *args) { CTypeDescrObject *ct, *ctresult; CDataObject *cd; PyObject *ob, *error_ob = Py_None; PyObject *py_rawerr, *infotuple = NULL; cif_description_t *cif_descr; ffi_closure *closure; Py_ssize_t size; if (!PyArg_ParseTuple(args, "O!O|O:callback", &CTypeDescr_Type, &ct, &ob, &error_ob)) return NULL; if (!(ct->ct_flags & CT_FUNCTIONPTR)) { PyErr_Format(PyExc_TypeError, "expected a function ctype, got '%s'", ct->ct_name); return NULL; } if (!PyCallable_Check(ob)) { PyErr_Format(PyExc_TypeError, "expected a callable object, not %.200s", Py_TYPE(ob)->tp_name); return NULL; } ctresult = (CTypeDescrObject *)PyTuple_GET_ITEM(ct->ct_stuff, 1); size = ctresult->ct_size; if (size < (Py_ssize_t)sizeof(ffi_arg)) size = sizeof(ffi_arg); py_rawerr = PyBytes_FromStringAndSize(NULL, size); if (py_rawerr == NULL) return NULL; memset(PyBytes_AS_STRING(py_rawerr), 0, size); if (error_ob != Py_None) { if (convert_from_object_fficallback( PyBytes_AS_STRING(py_rawerr), ctresult, error_ob) < 0) { Py_DECREF(py_rawerr); return NULL; } } infotuple = Py_BuildValue("OOO", ct, ob, py_rawerr); Py_DECREF(py_rawerr); if (infotuple == NULL) return NULL; closure = cffi_closure_alloc(); cd = PyObject_GC_New(CDataObject, &CDataOwningGC_Type); if (cd == NULL) goto error; Py_INCREF(ct); cd->c_type = ct; cd->c_data = (char *)closure; cd->c_weakreflist = NULL; PyObject_GC_Track(cd); cif_descr = (cif_description_t *)ct->ct_extra; if (cif_descr == NULL) { PyErr_SetString(PyExc_NotImplementedError, "callbacks with '...'"); goto error; } if (ffi_prep_closure(closure, &cif_descr->cif, invoke_callback, infotuple) != FFI_OK) { PyErr_SetString(PyExc_SystemError, "libffi failed to build this callback"); goto error; } assert(closure->user_data == infotuple); #ifdef WITH_THREAD PyEval_InitThreads(); #endif return (PyObject *)cd; error: closure->user_data = NULL; if (cd == NULL) cffi_closure_free(closure); else Py_DECREF(cd); Py_XDECREF(infotuple); return NULL; } static PyObject *b_new_enum_type(PyObject *self, PyObject *args) { char *ename; PyObject *enumerators, *enumvalues; PyObject *dict1 = NULL, *dict2 = NULL, *combined = NULL, *tmpkey = NULL; int name_size; CTypeDescrObject *td, *basetd; Py_ssize_t i, n; if (!PyArg_ParseTuple(args, "sO!O!O!:new_enum_type", &ename, &PyTuple_Type, &enumerators, &PyTuple_Type, &enumvalues, &CTypeDescr_Type, &basetd)) return NULL; n = PyTuple_GET_SIZE(enumerators); if (n != PyTuple_GET_SIZE(enumvalues)) { PyErr_SetString(PyExc_ValueError, "tuple args must have the same size"); return NULL; } if (!(basetd->ct_flags & (CT_PRIMITIVE_SIGNED|CT_PRIMITIVE_UNSIGNED))) { PyErr_SetString(PyExc_TypeError, "expected a primitive signed or unsigned base type"); return NULL; } dict1 = PyDict_New(); if (dict1 == NULL) goto error; dict2 = PyDict_New(); if (dict2 == NULL) goto error; for (i=n; --i >= 0; ) { long long lvalue; PyObject *value = PyTuple_GET_ITEM(enumvalues, i); tmpkey = PyTuple_GET_ITEM(enumerators, i); Py_INCREF(tmpkey); if (!PyText_Check(tmpkey)) { #if PY_MAJOR_VERSION < 3 if (PyUnicode_Check(tmpkey)) { char *text = PyText_AsUTF8(tmpkey); if (text == NULL) goto error; Py_DECREF(tmpkey); tmpkey = PyString_FromString(text); if (tmpkey == NULL) goto error; } else #endif { PyErr_SetString(PyExc_TypeError, "enumerators must be a list of strings"); goto error; } } if (convert_from_object((char*)&lvalue, basetd, value) < 0) goto error; /* out-of-range or badly typed 'value' */ if (PyDict_SetItem(dict1, tmpkey, value) < 0) goto error; if (PyDict_SetItem(dict2, value, tmpkey) < 0) goto error; Py_DECREF(tmpkey); tmpkey = NULL; } combined = PyTuple_Pack(2, dict1, dict2); if (combined == NULL) goto error; Py_CLEAR(dict2); Py_CLEAR(dict1); name_size = strlen(ename) + 1; td = ctypedescr_new(name_size); if (td == NULL) goto error; memcpy(td->ct_name, ename, name_size); td->ct_stuff = combined; td->ct_size = basetd->ct_size; td->ct_length = basetd->ct_length; /* alignment */ td->ct_extra = basetd->ct_extra; /* ffi type */ td->ct_flags = basetd->ct_flags | CT_IS_ENUM; td->ct_name_position = name_size - 1; return (PyObject *)td; error: Py_XDECREF(tmpkey); Py_XDECREF(combined); Py_XDECREF(dict2); Py_XDECREF(dict1); return NULL; } static PyObject *b_alignof(PyObject *self, PyObject *arg) { int align; if (!CTypeDescr_Check(arg)) { PyErr_SetString(PyExc_TypeError, "expected a 'ctype' object"); return NULL; } align = get_alignment((CTypeDescrObject *)arg); if (align < 0) return NULL; return PyInt_FromLong(align); } static PyObject *b_sizeof(PyObject *self, PyObject *arg) { Py_ssize_t size; if (CData_Check(arg)) { CDataObject *cd = (CDataObject *)arg; if (cd->c_type->ct_flags & CT_ARRAY) size = get_array_length(cd) * cd->c_type->ct_itemdescr->ct_size; else size = cd->c_type->ct_size; } else if (CTypeDescr_Check(arg)) { size = ((CTypeDescrObject *)arg)->ct_size; if (size < 0) { PyErr_Format(PyExc_ValueError, "ctype '%s' is of unknown size", ((CTypeDescrObject *)arg)->ct_name); return NULL; } } else { PyErr_SetString(PyExc_TypeError, "expected a 'cdata' or 'ctype' object"); return NULL; } return PyInt_FromSsize_t(size); } static PyObject *b_typeof(PyObject *self, PyObject *arg) { PyObject *res; if (!CData_Check(arg)) { PyErr_SetString(PyExc_TypeError, "expected a 'cdata' object"); return NULL; } res = (PyObject *)((CDataObject *)arg)->c_type; Py_INCREF(res); return res; } static PyObject *b_typeoffsetof(PyObject *self, PyObject *args) { PyObject *res, *fieldname; CTypeDescrObject *ct; CFieldObject *cf; Py_ssize_t offset; if (!PyArg_ParseTuple(args, "O!O:typeoffsetof", &CTypeDescr_Type, &ct, &fieldname)) return NULL; if (fieldname == Py_None) { if (!(ct->ct_flags & (CT_STRUCT|CT_UNION))) { PyErr_SetString(PyExc_TypeError, "expected a struct or union ctype"); return NULL; } res = (PyObject *)ct; offset = 0; } else { if (ct->ct_flags & CT_POINTER) ct = ct->ct_itemdescr; if (!(ct->ct_flags & (CT_STRUCT|CT_UNION)) || ct->ct_stuff == NULL) { PyErr_SetString(PyExc_TypeError, "expected an initialized struct or union ctype, " "or a pointer to one"); return NULL; } cf = (CFieldObject *)PyDict_GetItem(ct->ct_stuff, fieldname); if (cf == NULL) { PyErr_SetObject(PyExc_KeyError, fieldname); return NULL; } if (cf->cf_bitshift >= 0) { PyErr_SetString(PyExc_TypeError, "not supported for bitfields"); return NULL; } res = (PyObject *)cf->cf_type; offset = cf->cf_offset; } return Py_BuildValue("(On)", res, offset); } static PyObject *b_rawaddressof(PyObject *self, PyObject *args) { CTypeDescrObject *ct; CDataObject *cd; Py_ssize_t offset = 0; if (!PyArg_ParseTuple(args, "O!O!|n:rawaddressof", &CTypeDescr_Type, &ct, &CData_Type, &cd, &offset)) return NULL; if ((cd->c_type->ct_flags & (CT_STRUCT|CT_UNION|CT_IS_PTR_TO_OWNED)) == 0) { PyErr_SetString(PyExc_TypeError, "expected a 'cdata struct-or-union' object"); return NULL; } if ((ct->ct_flags & CT_POINTER) == 0) { PyErr_SetString(PyExc_TypeError, "expected a pointer ctype"); return NULL; } return new_simple_cdata(cd->c_data + offset, ct); } static PyObject *b_getcname(PyObject *self, PyObject *args) { CTypeDescrObject *ct; char *replace_with, *p, *s; Py_ssize_t namelen, replacelen; if (!PyArg_ParseTuple(args, "O!s:getcname", &CTypeDescr_Type, &ct, &replace_with)) return NULL; namelen = strlen(ct->ct_name); replacelen = strlen(replace_with); s = p = alloca(namelen + replacelen + 1); memcpy(p, ct->ct_name, ct->ct_name_position); p += ct->ct_name_position; memcpy(p, replace_with, replacelen); p += replacelen; memcpy(p, ct->ct_name + ct->ct_name_position, namelen - ct->ct_name_position); return PyText_FromStringAndSize(s, namelen + replacelen); } static PyObject *b_string(PyObject *self, PyObject *args) { CDataObject *cd; Py_ssize_t maxlen = -1; if (!PyArg_ParseTuple(args, "O!|n:string", &CData_Type, &cd, &maxlen)) return NULL; if (cd->c_type->ct_itemdescr != NULL && cd->c_type->ct_itemdescr->ct_flags & (CT_PRIMITIVE_CHAR | CT_PRIMITIVE_SIGNED | CT_PRIMITIVE_UNSIGNED)) { Py_ssize_t length = maxlen; if (cd->c_data == NULL) { PyObject *s = cdata_repr(cd); if (s != NULL) { PyErr_Format(PyExc_RuntimeError, "cannot use string() on %s", PyText_AS_UTF8(s)); Py_DECREF(s); } return NULL; } if (length < 0 && cd->c_type->ct_flags & CT_ARRAY) { length = get_array_length(cd); } if (cd->c_type->ct_itemdescr->ct_size == sizeof(char)) { const char *start = cd->c_data; if (length < 0) { /*READ(start, 1)*/ length = strlen(start); /*READ(start, length)*/ } else { const char *end; /*READ(start, length)*/ end = (const char *)memchr(start, 0, length); if (end != NULL) length = end - start; } return PyBytes_FromStringAndSize(start, length); } #ifdef HAVE_WCHAR_H else if (cd->c_type->ct_itemdescr->ct_flags & CT_PRIMITIVE_CHAR) { const wchar_t *start = (wchar_t *)cd->c_data; assert(cd->c_type->ct_itemdescr->ct_size == sizeof(wchar_t)); if (length < 0) { /*READ(start, sizeof(wchar_t))*/ length = 0; while (start[length]) length++; /*READ(start, sizeof(wchar_t) * length)*/ } else { /*READ(start, sizeof(wchar_t) * length)*/ maxlen = length; length = 0; while (length < maxlen && start[length]) length++; } return _my_PyUnicode_FromWideChar(start, length); } #endif } else if (cd->c_type->ct_flags & CT_IS_ENUM) { return convert_cdata_to_enum_string(cd, 0); } else if (cd->c_type->ct_flags & CT_IS_BOOL) { /* fall through to TypeError */ } else if (cd->c_type->ct_flags & (CT_PRIMITIVE_CHAR | CT_PRIMITIVE_SIGNED | CT_PRIMITIVE_UNSIGNED)) { /*READ(cd->c_data, cd->c_type->ct_size)*/ if (cd->c_type->ct_size == sizeof(char)) return PyBytes_FromStringAndSize(cd->c_data, 1); #ifdef HAVE_WCHAR_H else if (cd->c_type->ct_flags & CT_PRIMITIVE_CHAR) { assert(cd->c_type->ct_size == sizeof(wchar_t)); return _my_PyUnicode_FromWideChar((wchar_t *)cd->c_data, 1); } #endif } PyErr_Format(PyExc_TypeError, "string(): unexpected cdata '%s' argument", cd->c_type->ct_name); return NULL; } static PyObject *b_buffer(PyObject *self, PyObject *args) { CDataObject *cd; Py_ssize_t size = -1; if (!PyArg_ParseTuple(args, "O!|n:buffer", &CData_Type, &cd, &size)) return NULL; if (cd->c_type->ct_flags & CT_POINTER) { if (size < 0) size = cd->c_type->ct_itemdescr->ct_size; } else if (cd->c_type->ct_flags & CT_ARRAY) { if (size < 0) size = get_array_length(cd) * cd->c_type->ct_itemdescr->ct_size; } else { PyErr_Format(PyExc_TypeError, "expected a pointer or array cdata, got '%s'", cd->c_type->ct_name); return NULL; } if (size < 0) { PyErr_Format(PyExc_TypeError, "don't know the size pointed to by '%s'", cd->c_type->ct_name); return NULL; } /*WRITE(cd->c_data, size)*/ return minibuffer_new(cd->c_data, size, (PyObject *)cd); } static PyObject *b_get_errno(PyObject *self, PyObject *noarg) { int err; restore_errno_only(); err = errno; errno = 0; return PyInt_FromLong(err); } static PyObject *b_set_errno(PyObject *self, PyObject *args) { int i; if (!PyArg_ParseTuple(args, "i:set_errno", &i)) return NULL; errno = i; save_errno_only(); errno = 0; Py_INCREF(Py_None); return Py_None; } static PyObject *b_newp_handle(PyObject *self, PyObject *args) { CTypeDescrObject *ct; CDataObject *cd; PyObject *x; if (!PyArg_ParseTuple(args, "O!O", &CTypeDescr_Type, &ct, &x)) return NULL; if (!(ct->ct_flags & CT_IS_VOID_PTR)) { PyErr_Format(PyExc_TypeError, "needs 'void *', got '%s'", ct->ct_name); return NULL; } cd = (CDataObject *)PyObject_GC_New(CDataObject, &CDataOwningGC_Type); if (cd == NULL) return NULL; Py_INCREF(ct); cd->c_type = ct; Py_INCREF(x); cd->c_data = ((char *)x) - 42; cd->c_weakreflist = NULL; PyObject_GC_Track(cd); return (PyObject *)cd; } static PyObject *b_from_handle(PyObject *self, PyObject *arg) { CTypeDescrObject *ct; char *raw; PyObject *x; if (!CData_Check(arg)) { PyErr_SetString(PyExc_TypeError, "expected a 'cdata' object"); return NULL; } ct = ((CDataObject *)arg)->c_type; raw = ((CDataObject *)arg)->c_data; if (!(ct->ct_flags & CT_CAST_ANYTHING)) { PyErr_Format(PyExc_TypeError, "expected a 'cdata' object with a 'void *' out of " "new_handle(), got '%s'", ct->ct_name); return NULL; } if (!raw) { PyErr_SetString(PyExc_RuntimeError, "cannot use from_handle() on NULL pointer"); return NULL; } x = (PyObject *)(raw + 42); Py_INCREF(x); return x; } static PyObject *b__get_types(PyObject *self, PyObject *noarg) { return PyTuple_Pack(2, (PyObject *)&CData_Type, (PyObject *)&CTypeDescr_Type); } /************************************************************/ static char _testfunc0(char a, char b) { return a + b; } static long _testfunc1(int a, long b) { return (long)a + b; } static PY_LONG_LONG _testfunc2(PY_LONG_LONG a, PY_LONG_LONG b) { return a + b; } static double _testfunc3(float a, double b) { return a + b; } static float _testfunc4(float a, double b) { return (float)(a + b); } static void _testfunc5(void) { errno = errno + 15; } static int *_testfunc6(int *x) { static int y; y = *x - 1000; return &y; } struct _testfunc7_s { unsigned char a1; short a2; }; static short _testfunc7(struct _testfunc7_s inlined) { return inlined.a1 + inlined.a2; } static int _testfunc9(int num, ...) { va_list vargs; int i, total = 0; va_start(vargs, num); for (i=0; ia1 + (int)ptr->a2; } static long double _testfunc19(long double x, int count) { int i; for (i=0; ia1 + ptr->a2; } struct _testfunc21_s { int a, b, c, d, e, f, g, h, i, j; }; static int _testfunc21(struct _testfunc21_s inlined) { return ((inlined.a << 0) + (inlined.b << 1) + (inlined.c << 2) + (inlined.d << 3) + (inlined.e << 4) + (inlined.f << 5) + (inlined.g << 6) + (inlined.h << 7) + (inlined.i << 8) + (inlined.j << 9)); } struct _testfunc22_s { int a[10]; }; static struct _testfunc22_s _testfunc22(struct _testfunc22_s s1, struct _testfunc22_s s2) { struct _testfunc22_s result; int i; for (i=0; i<10; i++) result.a[i] = s1.a[i] - s2.a[i]; return result; } static int _testfunc23(char *p) { if (p) return 1000 * p[0]; return -42; } static PyObject *b__testfunc(PyObject *self, PyObject *args) { /* for testing only */ int i; void *f; if (!PyArg_ParseTuple(args, "i:_testfunc", &i)) return NULL; switch (i) { case 0: f = &_testfunc0; break; case 1: f = &_testfunc1; break; case 2: f = &_testfunc2; break; case 3: f = &_testfunc3; break; case 4: f = &_testfunc4; break; case 5: f = &_testfunc5; break; case 6: f = &_testfunc6; break; case 7: f = &_testfunc7; break; case 8: f = stderr; break; case 9: f = &_testfunc9; break; case 10: f = &_testfunc10; break; case 11: f = &_testfunc11; break; case 12: f = &_testfunc12; break; case 13: f = &_testfunc13; break; case 14: f = &_testfunc14; break; case 15: f = &_testfunc15; break; case 16: f = &_testfunc16; break; case 17: f = &_testfunc17; break; case 18: f = &_testfunc18; break; case 19: f = &_testfunc19; break; case 20: f = &_testfunc20; break; case 21: f = &_testfunc21; break; case 22: f = &_testfunc22; break; case 23: f = &_testfunc23; break; default: PyErr_SetNone(PyExc_ValueError); return NULL; } return PyLong_FromVoidPtr(f); } static PyMethodDef FFIBackendMethods[] = { {"load_library", b_load_library, METH_VARARGS}, {"new_primitive_type", b_new_primitive_type, METH_VARARGS}, {"new_pointer_type", b_new_pointer_type, METH_VARARGS}, {"new_array_type", b_new_array_type, METH_VARARGS}, {"new_void_type", b_new_void_type, METH_NOARGS}, {"new_struct_type", b_new_struct_type, METH_VARARGS}, {"new_union_type", b_new_union_type, METH_VARARGS}, {"complete_struct_or_union", b_complete_struct_or_union, METH_VARARGS}, {"new_function_type", b_new_function_type, METH_VARARGS}, {"new_enum_type", b_new_enum_type, METH_VARARGS}, {"newp", b_newp, METH_VARARGS}, {"cast", b_cast, METH_VARARGS}, {"callback", b_callback, METH_VARARGS}, {"alignof", b_alignof, METH_O}, {"sizeof", b_sizeof, METH_O}, {"typeof", b_typeof, METH_O}, {"typeoffsetof", b_typeoffsetof, METH_VARARGS}, {"rawaddressof", b_rawaddressof, METH_VARARGS}, {"getcname", b_getcname, METH_VARARGS}, {"string", b_string, METH_VARARGS}, {"buffer", b_buffer, METH_VARARGS}, {"get_errno", b_get_errno, METH_NOARGS}, {"set_errno", b_set_errno, METH_VARARGS}, {"newp_handle", b_newp_handle, METH_VARARGS}, {"from_handle", b_from_handle, METH_O}, #ifdef MS_WIN32 {"getwinerror", b_getwinerror, METH_VARARGS}, #endif {"_get_types", b__get_types, METH_NOARGS}, {"_testfunc", b__testfunc, METH_VARARGS}, {NULL, NULL} /* Sentinel */ }; /************************************************************/ /* Functions used by '_cffi_N.so', the generated modules */ #define _cffi_to_c_SIGNED_FN(RETURNTYPE, SIZE) \ static RETURNTYPE _cffi_to_c_i##SIZE(PyObject *obj) { \ PY_LONG_LONG tmp = _my_PyLong_AsLongLong(obj); \ if ((tmp > (PY_LONG_LONG)((1ULL<<(SIZE-1)) - 1)) || \ (tmp < (PY_LONG_LONG)(-(1ULL<<(SIZE-1))))) \ if (!PyErr_Occurred()) \ return (RETURNTYPE)_convert_overflow(obj, #SIZE "-bit int"); \ return (RETURNTYPE)tmp; \ } #define _cffi_to_c_UNSIGNED_FN(RETURNTYPE, SIZE) \ static RETURNTYPE _cffi_to_c_u##SIZE(PyObject *obj) { \ unsigned PY_LONG_LONG tmp = _my_PyLong_AsUnsignedLongLong(obj, 1); \ if (tmp > ~(((unsigned PY_LONG_LONG)-2) << (SIZE-1))) \ if (!PyErr_Occurred()) \ return (RETURNTYPE)_convert_overflow(obj, \ #SIZE "-bit unsigned int"); \ return (RETURNTYPE)tmp; \ } _cffi_to_c_SIGNED_FN(int, 8) _cffi_to_c_SIGNED_FN(int, 16) _cffi_to_c_SIGNED_FN(int, 32) _cffi_to_c_SIGNED_FN(PY_LONG_LONG, 64) _cffi_to_c_UNSIGNED_FN(int, 8) _cffi_to_c_UNSIGNED_FN(int, 16) _cffi_to_c_UNSIGNED_FN(unsigned int, 32) _cffi_to_c_UNSIGNED_FN(unsigned PY_LONG_LONG, 64) static PyObject *_cffi_from_c_pointer(char *ptr, CTypeDescrObject *ct) { return convert_to_object((char *)&ptr, ct); } static char *_cffi_to_c_pointer(PyObject *obj, CTypeDescrObject *ct) { char *result; if (convert_from_object((char *)&result, ct, obj) < 0) { if ((ct->ct_flags & CT_POINTER) && (ct->ct_itemdescr->ct_flags & CT_IS_FILE) && PyFile_Check(obj)) { PyErr_Clear(); return (char *)PyFile_AsFile(obj); } return NULL; } return result; } static long double _cffi_to_c_long_double(PyObject *obj) { if (CData_Check(obj) && (((CDataObject *)obj)->c_type->ct_flags & CT_IS_LONGDOUBLE)) { char *data = ((CDataObject *)obj)->c_data; /*READ(data, sizeof(long double))*/ return read_raw_longdouble_data(data); } else return PyFloat_AsDouble(obj); } static _Bool _cffi_to_c__Bool(PyObject *obj) { PY_LONG_LONG tmp = _my_PyLong_AsLongLong(obj); if (tmp == 0) return 0; else if (tmp == 1) return 1; else if (PyErr_Occurred()) return (_Bool)-1; else return (_Bool)_convert_overflow(obj, "_Bool"); } static PyObject *_cffi_get_struct_layout(Py_ssize_t nums[]) { PyObject *result; int count = 0; while (nums[count] >= 0) count++; result = PyList_New(count); if (result == NULL) return NULL; while (--count >= 0) { PyObject *o = PyInt_FromSsize_t(nums[count]); if (o == NULL) { Py_DECREF(result); return NULL; } PyList_SET_ITEM(result, count, o); } return result; } static PyObject *_cffi_from_c_char(char x) { return PyBytes_FromStringAndSize(&x, 1); } #ifdef HAVE_WCHAR_H static PyObject *_cffi_from_c_wchar_t(wchar_t x) { return _my_PyUnicode_FromWideChar(&x, 1); } #endif static void *cffi_exports[] = { 0, _cffi_to_c_i8, _cffi_to_c_u8, _cffi_to_c_i16, _cffi_to_c_u16, _cffi_to_c_i32, _cffi_to_c_u32, _cffi_to_c_i64, _cffi_to_c_u64, _convert_to_char, _cffi_from_c_pointer, _cffi_to_c_pointer, _cffi_get_struct_layout, restore_errno, save_errno, _cffi_from_c_char, convert_to_object, convert_from_object, convert_struct_to_owning_object, #ifdef HAVE_WCHAR_H _convert_to_wchar_t, _cffi_from_c_wchar_t, #else 0, 0, #endif _cffi_to_c_long_double, _cffi_to_c__Bool, _prepare_pointer_call_argument, convert_array_from_object, }; /************************************************************/ #if PY_MAJOR_VERSION >= 3 static struct PyModuleDef FFIBackendModuleDef = { PyModuleDef_HEAD_INIT, "_cffi_backend", NULL, -1, FFIBackendMethods, NULL, NULL, NULL, NULL }; #define INITERROR return NULL PyMODINIT_FUNC PyInit__cffi_backend(void) #else #define INITERROR return PyMODINIT_FUNC init_cffi_backend(void) #endif { PyObject *m, *v; v = PySys_GetObject("version"); if (v == NULL || !PyText_Check(v) || strncmp(PyText_AS_UTF8(v), PY_VERSION, 3) != 0) { PyErr_Format(PyExc_ImportError, "this module was compiled for Python %c%c%c", PY_VERSION[0], PY_VERSION[1], PY_VERSION[2]); INITERROR; } #if PY_MAJOR_VERSION >= 3 m = PyModule_Create(&FFIBackendModuleDef); #else m = Py_InitModule("_cffi_backend", FFIBackendMethods); #endif if (m == NULL) INITERROR; if (PyType_Ready(&dl_type) < 0) INITERROR; if (PyType_Ready(&CTypeDescr_Type) < 0) INITERROR; if (PyType_Ready(&CField_Type) < 0) INITERROR; if (PyType_Ready(&CData_Type) < 0) INITERROR; if (PyType_Ready(&CDataOwning_Type) < 0) INITERROR; if (PyType_Ready(&CDataOwningGC_Type) < 0) INITERROR; if (PyType_Ready(&CDataIter_Type) < 0) INITERROR; if (PyType_Ready(&MiniBuffer_Type) < 0) INITERROR; v = PyText_FromString("_cffi_backend"); if (v == NULL || PyDict_SetItemString(CData_Type.tp_dict, "__module__", v) < 0) INITERROR; v = PyText_FromString(""); if (v == NULL || PyDict_SetItemString(CData_Type.tp_dict, "__name__", v) < 0) INITERROR; v = PyCapsule_New((void *)cffi_exports, "cffi", NULL); if (v == NULL || PyModule_AddObject(m, "_C_API", v) < 0) INITERROR; v = PyText_FromString("0.8.6"); if (v == NULL || PyModule_AddObject(m, "__version__", v) < 0) INITERROR; if (PyModule_AddIntConstant(m, "FFI_DEFAULT_ABI", FFI_DEFAULT_ABI) < 0 || #if defined(MS_WIN32) && !defined(_WIN64) PyModule_AddIntConstant(m, "FFI_STDCALL", FFI_STDCALL) < 0 || #endif #ifdef FFI_CDECL PyModule_AddIntConstant(m, "FFI_CDECL", FFI_CDECL) < 0 || /* win32 */ #else PyModule_AddIntConstant(m, "FFI_CDECL", FFI_DEFAULT_ABI) < 0 || #endif #ifdef MS_WIN32 # ifdef _WIN64 PyModule_AddIntConstant(m, "_WIN", 64) < 0 || /* win64 */ # else PyModule_AddIntConstant(m, "_WIN", 32) < 0 || /* win32 */ # endif #endif PyModule_AddIntConstant(m, "RTLD_LAZY", RTLD_LAZY) < 0 || PyModule_AddIntConstant(m, "RTLD_NOW", RTLD_NOW) < 0 || PyModule_AddIntConstant(m, "RTLD_GLOBAL", RTLD_GLOBAL) < 0 || #ifdef RTLD_LOCAL PyModule_AddIntConstant(m, "RTLD_LOCAL", RTLD_LOCAL) < 0 || #else PyModule_AddIntConstant(m, "RTLD_LOCAL", 0) < 0 || #endif #ifdef RTLD_NODELETE PyModule_AddIntConstant(m, "RTLD_NODELETE", RTLD_NODELETE) < 0 || #endif #ifdef RTLD_NOLOAD PyModule_AddIntConstant(m, "RTLD_NOLOAD", RTLD_NOLOAD) < 0 || #endif #ifdef RTLD_DEEPBIND PyModule_AddIntConstant(m, "RTLD_DEEPBIND", RTLD_DEEPBIND) < 0 || #endif 0) INITERROR; init_errno(); #if PY_MAJOR_VERSION >= 3 if (init_file_emulator() < 0) INITERROR; return m; #endif }