| #define PY_SSIZE_T_CLEAN | |
| #include <Python.h> | |
| #include "structmember.h" | |
| #define CFFI_VERSION "1.15.0" | |
| #ifdef MS_WIN32 | |
| #include <windows.h> | |
| #include "misc_win32.h" | |
| #else | |
| #include <stddef.h> | |
| #include <stdint.h> | |
| #include <dlfcn.h> | |
| #include <errno.h> | |
| #include <ffi.h> | |
| #include <sys/mman.h> | |
| #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 <malloc.h> /* 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 <stdint.h> | |
| # endif | |
| # if _MSC_VER < 1800 /* MSVC < 2013 */ | |
| typedef unsigned char _Bool; | |
| # endif | |
| #else | |
| # include <stdint.h> | |
| # if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux) | |
| # include <alloca.h> | |
| # endif | |
| #endif | |
| /* Define the following macro ONLY if you trust libffi's version of | |
| * ffi_closure_alloc() more than the code in malloc_closure.h. | |
| * IMPORTANT: DO NOT ENABLE THIS ON LINUX, unless you understand exactly | |
| * why I recommend against it and decide that you trust it more than my | |
| * analysis below. | |
| * | |
| * There are two versions of this code: one inside libffi itself, and | |
| * one inside malloc_closure.h here. Both should be fine as long as the | |
| * Linux distribution does _not_ enable extra security features. If it | |
| * does, then the code in malloc_closure.h will cleanly crash because | |
| * there is no reasonable way to obtain a read-write-execute memory | |
| * page. On the other hand, the code in libffi will appear to | |
| * work---but will actually randomly crash after a fork() if the child | |
| * does not immediately call exec(). This second crash is of the kind | |
| * that can be turned into an attack vector by a motivated attacker. | |
| * So, _enabling_ extra security features _opens_ an attack vector. | |
| * That sounds like a horribly bad idea to me, and is the reason for why | |
| * I prefer CFFI crashing cleanly. | |
| * | |
| * Currently, we use libffi's ffi_closure_alloc() on NetBSD. It is | |
| * known that on the NetBSD kernel, a different strategy is used which | |
| * should not be open to the fork() bug. | |
| * | |
| * This is also used on macOS, provided we are executing on macOS 10.15 or | |
| * above. It's a mess because it needs runtime checks in that case. | |
| */ | |
| #ifdef __NetBSD__ | |
| # define CFFI_CHECK_FFI_CLOSURE_ALLOC 1 | |
| # define CFFI_CHECK_FFI_CLOSURE_ALLOC_MAYBE 1 | |
| # define CFFI_CHECK_FFI_PREP_CLOSURE_LOC 1 | |
| # define CFFI_CHECK_FFI_PREP_CLOSURE_LOC_MAYBE 1 | |
| # define CFFI_CHECK_FFI_PREP_CIF_VAR 0 | |
| # define CFFI_CHECK_FFI_PREP_CIF_VAR_MAYBE 0 | |
| #elif defined(__APPLE__) && defined(FFI_AVAILABLE_APPLE) | |
| # define CFFI_CHECK_FFI_CLOSURE_ALLOC __builtin_available(macos 10.15, ios 13, watchos 6, tvos 13, *) | |
| # define CFFI_CHECK_FFI_CLOSURE_ALLOC_MAYBE 1 | |
| # define CFFI_CHECK_FFI_PREP_CLOSURE_LOC __builtin_available(macos 10.15, ios 13, watchos 6, tvos 13, *) | |
| # define CFFI_CHECK_FFI_PREP_CLOSURE_LOC_MAYBE 1 | |
| # define CFFI_CHECK_FFI_PREP_CIF_VAR __builtin_available(macos 10.15, ios 13, watchos 6, tvos 13, *) | |
| # define CFFI_CHECK_FFI_PREP_CIF_VAR_MAYBE 1 | |
| #else | |
| # define CFFI_CHECK_FFI_CLOSURE_ALLOC 0 | |
| # define CFFI_CHECK_FFI_CLOSURE_ALLOC_MAYBE 0 | |
| # define CFFI_CHECK_FFI_PREP_CLOSURE_LOC 0 | |
| # define CFFI_CHECK_FFI_PREP_CLOSURE_LOC_MAYBE 0 | |
| # define CFFI_CHECK_FFI_PREP_CIF_VAR 0 | |
| # define CFFI_CHECK_FFI_PREP_CIF_VAR_MAYBE 0 | |
| #endif | |
| /* always includes this, even if it turns out not to be used on NetBSD | |
| because calls are behind "if (0)" */ | |
| #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 | |
| # if PY_VERSION_HEX >= 0x03030000 | |
| # define PyText_GetSize PyUnicode_GetLength | |
| # else | |
| # define PyText_GetSize PyUnicode_GetSize | |
| # endif | |
| # define PyText_FromString PyUnicode_FromString | |
| # define PyText_FromStringAndSize PyUnicode_FromStringAndSize | |
| # define PyText_InternInPlace PyUnicode_InternInPlace | |
| # define PyText_InternFromString PyUnicode_InternFromString | |
| # 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 PyText_InternFromString PyString_InternFromString | |
| # 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 | |
| # define PyInt_AsLong PyLong_AsLong | |
| #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 | |
| # undef PyCapsule_GetPointer | |
| # undef PyCapsule_New | |
| # define PyCapsule_GetPointer(capsule, name) \ | |
| (PyCObject_AsVoidPtr(capsule)) | |
| # define PyCapsule_New(pointer, name, destructor) \ | |
| (PyCObject_FromVoidPtr(pointer, destructor)) | |
| #endif | |
| #if PY_VERSION_HEX < 0x030900a4 | |
| # define Py_SET_REFCNT(obj, val) (Py_REFCNT(obj) = (val)) | |
| #endif | |
| #if PY_VERSION_HEX >= 0x03080000 | |
| # define USE_WRITEUNRAISABLEMSG | |
| #endif | |
| /************************************************************/ | |
| /* base type flag: exactly one of the following: */ | |
| #define CT_PRIMITIVE_SIGNED 0x001 /* signed integer */ | |
| #define CT_PRIMITIVE_UNSIGNED 0x002 /* unsigned integer */ | |
| #define CT_PRIMITIVE_CHAR 0x004 /* char, wchar_t, charN_t */ | |
| #define CT_PRIMITIVE_FLOAT 0x008 /* float, double, long double */ | |
| #define CT_POINTER 0x010 /* pointer, excluding ptr-to-func */ | |
| #define CT_ARRAY 0x020 /* array */ | |
| #define CT_STRUCT 0x040 /* struct */ | |
| #define CT_UNION 0x080 /* union */ | |
| #define CT_FUNCTIONPTR 0x100 /* pointer to function */ | |
| #define CT_VOID 0x200 /* void */ | |
| #define CT_PRIMITIVE_COMPLEX 0x400 /* float _Complex, double _Complex */ | |
| /* other flags that may also be set in addition to the base flag: */ | |
| #define CT_IS_VOIDCHAR_PTR 0x00001000 | |
| #define CT_PRIMITIVE_FITS_LONG 0x00002000 | |
| #define CT_IS_OPAQUE 0x00004000 | |
| #define CT_IS_ENUM 0x00008000 | |
| #define CT_IS_PTR_TO_OWNED 0x00010000 /* only owned if CDataOwning_Type */ | |
| #define CT_CUSTOM_FIELD_POS 0x00020000 | |
| #define CT_IS_LONGDOUBLE 0x00040000 | |
| #define CT_IS_BOOL 0x00080000 | |
| #define CT_IS_FILE 0x00100000 | |
| #define CT_IS_VOID_PTR 0x00200000 | |
| #define CT_WITH_VAR_ARRAY 0x00400000 /* with open-ended array, anywhere */ | |
| /* unused 0x00800000 */ | |
| #define CT_LAZY_FIELD_LIST 0x01000000 | |
| #define CT_WITH_PACKED_CHANGE 0x02000000 | |
| #define CT_IS_SIGNED_WCHAR 0x04000000 | |
| #define CT_PRIMITIVE_ANY (CT_PRIMITIVE_SIGNED | \ | |
| CT_PRIMITIVE_UNSIGNED | \ | |
| CT_PRIMITIVE_CHAR | \ | |
| CT_PRIMITIVE_FLOAT | \ | |
| CT_PRIMITIVE_COMPLEX) | |
| 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 */ | |
| PyObject *ct_unique_key; /* key in unique_cache (a string, but not | |
| human-readable) */ | |
| 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; | |
| unsigned char cf_flags; /* BF_... */ | |
| struct cfieldobject_s *cf_next; | |
| } CFieldObject; | |
| #define BS_REGULAR (-1) /* a regular field, not with bitshift */ | |
| #define BS_EMPTY_ARRAY (-2) /* a field declared 'type[0]' or 'type[]' */ | |
| #define BF_IGNORE_IN_CTOR 0x01 /* union field not in the first place */ | |
| static PyTypeObject CTypeDescr_Type; | |
| static PyTypeObject CField_Type; | |
| static PyTypeObject CData_Type; | |
| static PyTypeObject CDataOwning_Type; | |
| static PyTypeObject CDataOwningGC_Type; | |
| static PyTypeObject CDataFromBuf_Type; | |
| static PyTypeObject CDataGCP_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 || \ | |
| Py_TYPE(ob) == &CDataFromBuf_Type || \ | |
| Py_TYPE(ob) == &CDataGCP_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; /* for ffi.new_handle() or ffi.new("struct *") */ | |
| } CDataObject_own_structptr; | |
| typedef struct { | |
| CDataObject head; | |
| Py_ssize_t length; /* same as CDataObject_own_length up to here */ | |
| Py_buffer *bufferview; | |
| } CDataObject_frombuf; | |
| typedef struct { | |
| CDataObject head; | |
| Py_ssize_t length; /* same as CDataObject_own_length up to here */ | |
| PyObject *origobj; | |
| PyObject *destructor; | |
| } CDataObject_gcp; | |
| typedef struct { | |
| CDataObject head; | |
| ffi_closure *closure; | |
| } CDataObject_closure; | |
| 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; | |
| #define ADD_WRAPAROUND(x, y) ((Py_ssize_t)(((size_t)(x)) + ((size_t)(y)))) | |
| #define MUL_WRAPAROUND(x, y) ((Py_ssize_t)(((size_t)(x)) * ((size_t)(y)))) | |
| /* whenever running Python code, the errno is saved in this thread-local | |
| variable */ | |
| #ifndef MS_WIN32 | |
| # include "misc_thread_posix.h" | |
| #endif | |
| #include "minibuffer.h" | |
| #if PY_MAJOR_VERSION >= 3 | |
| # include "file_emulator.h" | |
| #endif | |
| #ifdef PyUnicode_KIND /* Python >= 3.3 */ | |
| # include "wchar_helper_3.h" | |
| #else | |
| # include "wchar_helper.h" | |
| #endif | |
| #include "../cffi/_cffi_errors.h" | |
| typedef struct _cffi_allocator_s { | |
| PyObject *ca_alloc, *ca_free; | |
| int ca_dont_clear; | |
| } cffi_allocator_t; | |
| static const cffi_allocator_t default_allocator = { NULL, NULL, 0 }; | |
| static PyObject *FFIError; | |
| static PyObject *unique_cache; | |
| /************************************************************/ | |
| 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; | |
| ct->ct_unique_key = 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("<ctype '%s'>", ct->ct_name); | |
| } | |
| static void | |
| ctypedescr_dealloc(CTypeDescrObject *ct) | |
| { | |
| PyObject_GC_UnTrack(ct); | |
| if (ct->ct_weakreflist != NULL) | |
| PyObject_ClearWeakRefs((PyObject *) ct); | |
| if (ct->ct_unique_key != NULL) { | |
| /* revive dead object temporarily for DelItem */ | |
| Py_SET_REFCNT(ct, 43); | |
| PyDict_DelItem(unique_cache, ct->ct_unique_key); | |
| assert(Py_REFCNT(ct) == 42); | |
| Py_SET_REFCNT(ct, 0); | |
| Py_DECREF(ct->ct_unique_key); | |
| } | |
| 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 */ | |
| /* returns 0 if the struct ctype is opaque, 1 if it is not, or -1 if | |
| an exception occurs */ | |
| #define force_lazy_struct(ct) \ | |
| ((ct)->ct_stuff != NULL ? 1 : do_realize_lazy_struct(ct)) | |
| static int do_realize_lazy_struct(CTypeDescrObject *ct); | |
| /* forward, implemented in realize_c_type.c */ | |
| 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; | |
| if (force_lazy_struct(ct) < 0) | |
| return NULL; | |
| 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.CType", | |
| 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}, | |
| {"flags", T_UBYTE, OFF(cf_flags), 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; | |
| } | |
| #ifdef __GNUC__ | |
| /* This is a workaround for what I think is a GCC bug on several | |
| platforms. See issue #378. */ | |
| __attribute__((noinline)) | |
| #endif | |
| void _cffi_memcpy(char *target, const void *src, size_t size) | |
| { | |
| memcpy(target, src, size); | |
| } | |
| #define _write_raw_data(type) \ | |
| do { \ | |
| if (size == sizeof(type)) { \ | |
| type r = (type)source; \ | |
| _cffi_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 Py_complex | |
| read_raw_complex_data(char *target, int size) | |
| { | |
| Py_complex r = {0.0, 0.0}; | |
| if (size == 2*sizeof(float)) { | |
| float real_part, imag_part; | |
| memcpy(&real_part, target + 0, sizeof(float)); | |
| memcpy(&imag_part, target + sizeof(float), sizeof(float)); | |
| r.real = real_part; | |
| r.imag = imag_part; | |
| return r; | |
| } | |
| if (size == 2*sizeof(double)) { | |
| memcpy(&r, target, 2*sizeof(double)); | |
| return r; | |
| } | |
| Py_FatalError("read_raw_complex_data: bad complex size"); | |
| return r; | |
| } | |
| 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); | |
| } | |
| #define _write_raw_complex_data(type) \ | |
| do { \ | |
| if (size == 2*sizeof(type)) { \ | |
| type r = (type)source.real; \ | |
| type i = (type)source.imag; \ | |
| _cffi_memcpy(target, &r, sizeof(type)); \ | |
| _cffi_memcpy(target+sizeof(type), &i, sizeof(type)); \ | |
| return; \ | |
| } \ | |
| } while(0) | |
| static void | |
| write_raw_complex_data(char *target, Py_complex source, int size) | |
| { | |
| _write_raw_complex_data(float); | |
| _write_raw_complex_data(double); | |
| Py_FatalError("write_raw_complex_data: bad complex size"); | |
| } | |
| 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 PyObject * | |
| new_sized_cdata(char *data, CTypeDescrObject *ct, Py_ssize_t length) | |
| { | |
| CDataObject_own_length *scd; | |
| 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 = data; | |
| scd->head.c_weakreflist = NULL; | |
| scd->length = length; | |
| return (PyObject *)scd; | |
| } | |
| 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 <cdata 'int[]'> here, because we don't | |
| know the length to give it. As a compromize, returns | |
| <cdata 'int *'> 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) { | |
| if (ct->ct_flags & CT_IS_BOOL) { | |
| PyObject *x; | |
| switch ((int)value) { | |
| case 0: x = Py_False; break; | |
| case 1: x = Py_True; break; | |
| default: | |
| PyErr_Format(PyExc_ValueError, | |
| "got a _Bool of value %d, expected 0 or 1", | |
| (int)value); | |
| return NULL; | |
| } | |
| Py_INCREF(x); | |
| return x; | |
| } | |
| 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)*/ | |
| switch (ct->ct_size) { | |
| case sizeof(char): | |
| return PyBytes_FromStringAndSize(data, 1); | |
| case 2: | |
| return _my_PyUnicode_FromChar16((cffi_char16_t *)data, 1); | |
| case 4: | |
| return _my_PyUnicode_FromChar32((cffi_char32_t *)data, 1); | |
| } | |
| } | |
| else if (ct->ct_flags & CT_PRIMITIVE_COMPLEX) { | |
| Py_complex value = read_raw_complex_data(data, ct->ct_size); | |
| return PyComplex_FromCComplex(value); | |
| } | |
| 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; | |
| } | |
| static cffi_char16_t _convert_to_char16_t(PyObject *init) | |
| { | |
| char err_got[80]; | |
| err_got[0] = 0; | |
| if (PyUnicode_Check(init)) { | |
| cffi_char16_t ordinal; | |
| if (_my_PyUnicode_AsSingleChar16(init, &ordinal, err_got) == 0) | |
| return ordinal; | |
| } | |
| if (CData_Check(init) && | |
| (((CDataObject *)init)->c_type->ct_flags & CT_PRIMITIVE_CHAR) && | |
| (((CDataObject *)init)->c_type->ct_size == 2)) { | |
| char *data = ((CDataObject *)init)->c_data; | |
| /*READ(data, 2)*/ | |
| return *(cffi_char16_t *)data; | |
| } | |
| PyErr_Format(PyExc_TypeError, | |
| "initializer for ctype 'char16_t' must be a unicode string " | |
| "of length 1, not %.200s", | |
| err_got[0] == 0 ? Py_TYPE(init)->tp_name : err_got); | |
| return (cffi_char16_t)-1; | |
| } | |
| static cffi_char32_t _convert_to_char32_t(PyObject *init) | |
| { | |
| char err_got[80]; | |
| err_got[0] = 0; | |
| if (PyUnicode_Check(init)) { | |
| cffi_char32_t ordinal; | |
| if (_my_PyUnicode_AsSingleChar32(init, &ordinal, err_got) == 0) | |
| return ordinal; | |
| } | |
| if (CData_Check(init) && | |
| (((CDataObject *)init)->c_type->ct_flags & CT_PRIMITIVE_CHAR) && | |
| (((CDataObject *)init)->c_type->ct_size == 4)) { | |
| char *data = ((CDataObject *)init)->c_data; | |
| /*READ(data, 4)*/ | |
| return *(cffi_char32_t *)data; | |
| } | |
| PyErr_Format(PyExc_TypeError, | |
| "initializer for ctype 'char32_t' must be a unicode string " | |
| "of length 1, not %.200s", | |
| err_got[0] == 0 ? Py_TYPE(init)->tp_name : err_got); | |
| return (cffi_char32_t)-1; | |
| } | |
| static int _convert_error(PyObject *init, CTypeDescrObject *ct, | |
| const char *expected) | |
| { | |
| if (CData_Check(init)) { | |
| CTypeDescrObject *ct2 = ((CDataObject *)init)->c_type; | |
| if (strcmp(ct->ct_name, ct2->ct_name) != 0) | |
| PyErr_Format(PyExc_TypeError, | |
| "initializer for ctype '%s' must be a %s, " | |
| "not cdata '%s'", | |
| ct->ct_name, expected, ct2->ct_name); | |
| else if (ct != ct2) { | |
| /* in case we'd give the error message "initializer for | |
| ctype 'A' must be a pointer to same type, not cdata | |
| 'B'", but with A=B, then give instead a different error | |
| message to try to clear up the confusion */ | |
| PyErr_Format(PyExc_TypeError, | |
| "initializer for ctype '%s' appears indeed to be '%s'," | |
| " but the types are different (check that you are not" | |
| " e.g. mixing up different ffi instances)", | |
| ct->ct_name, ct2->ct_name); | |
| } | |
| else | |
| { | |
| PyErr_Format(PyExc_SystemError, | |
| "initializer for ctype '%s' is correct, but we get " | |
| "an internal mismatch--please report a bug", | |
| ct->ct_name); | |
| } | |
| } | |
| else | |
| PyErr_Format(PyExc_TypeError, | |
| "initializer for ctype '%s' must be a %s, " | |
| "not %.200s", | |
| ct->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(CTypeDescrObject *ctitem, 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 */ | |
| int length; | |
| if (ctitem->ct_size == 2) | |
| length = _my_PyUnicode_SizeAsChar16(value); | |
| else | |
| length = _my_PyUnicode_SizeAsChar32(value); | |
| return length + 1; | |
| } | |
| else { | |
| Py_ssize_t explicitlength; | |
| explicitlength = PyNumber_AsSsize_t(value, PyExc_OverflowError); | |
| if (explicitlength < 0) { | |
| if (PyErr_Occurred()) { | |
| if (PyErr_ExceptionMatches(PyExc_TypeError)) | |
| PyErr_Format(PyExc_TypeError, | |
| "expected new array length or list/tuple/str, " | |
| "not %.200s", Py_TYPE(value)->tp_name); | |
| } | |
| else | |
| 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 | |
| add_varsize_length(Py_ssize_t offset, Py_ssize_t itemsize, | |
| Py_ssize_t varsizelength, Py_ssize_t *optvarsize) | |
| { | |
| /* update '*optvarsize' to account for an array of 'varsizelength' | |
| elements, each of size 'itemsize', that starts at 'offset'. */ | |
| Py_ssize_t size = ADD_WRAPAROUND(offset, | |
| MUL_WRAPAROUND(itemsize, varsizelength)); | |
| if (size < 0 || | |
| ((size - offset) / itemsize) != varsizelength) { | |
| PyErr_SetString(PyExc_OverflowError, | |
| "array size would overflow a Py_ssize_t"); | |
| return -1; | |
| } | |
| if (size > *optvarsize) | |
| *optvarsize = size; | |
| return 0; | |
| } | |
| static int | |
| convert_struct_from_object(char *data, CTypeDescrObject *ct, PyObject *init, | |
| Py_ssize_t *optvarsize); /* forward */ | |
| 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( | |
| cf->cf_type->ct_itemdescr, &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 */ | |
| assert(data == NULL); | |
| return add_varsize_length(cf->cf_offset, | |
| cf->cf_type->ct_itemdescr->ct_size, | |
| varsizelength, | |
| optvarsize); | |
| } | |
| /* 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 if ((cf->cf_type->ct_flags & CT_WITH_VAR_ARRAY) != 0 && | |
| !CData_Check(value)) { | |
| Py_ssize_t subsize = cf->cf_type->ct_size; | |
| if (convert_struct_from_object(NULL, cf->cf_type, value, &subsize) < 0) | |
| return -1; | |
| return add_varsize_length(cf->cf_offset, 1, subsize, optvarsize); | |
| } | |
| else | |
| return 0; | |
| } | |
| static int | |
| must_be_array_of_zero_or_one(const char *data, Py_ssize_t n) | |
| { | |
| Py_ssize_t i; | |
| for (i = 0; i < n; i++) { | |
| if (((unsigned char)data[i]) > 1) { | |
| PyErr_SetString(PyExc_ValueError, | |
| "an array of _Bool can only contain \\x00 or \\x01"); | |
| return -1; | |
| } | |
| } | |
| 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 | |
| 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; i<n; i++) { | |
| if (convert_from_object(data, ctitem, items[i]) < 0) | |
| return -1; | |
| data += ctitem->ct_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); | |
| if (ctitem->ct_flags & CT_IS_BOOL) | |
| if (must_be_array_of_zero_or_one(srcdata, n) < 0) | |
| return -1; | |
| memcpy(data, srcdata, n); | |
| return 0; | |
| } | |
| else { | |
| Py_ssize_t n; | |
| if (!PyUnicode_Check(init)) { | |
| expected = "unicode or list or tuple"; | |
| goto cannot_convert; | |
| } | |
| if (ctitem->ct_size == 4) | |
| n = _my_PyUnicode_SizeAsChar32(init); | |
| else | |
| n = _my_PyUnicode_SizeAsChar16(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++; | |
| if (ctitem->ct_size == 4) | |
| return _my_PyUnicode_AsChar32(init, (cffi_char32_t *)data, n); | |
| else | |
| return _my_PyUnicode_AsChar16(init, (cffi_char16_t *)data, n); | |
| } | |
| } | |
| else { | |
| expected = "list or tuple"; | |
| goto cannot_convert; | |
| } | |
| cannot_convert: | |
| if ((ct->ct_flags & CT_ARRAY) && CData_Check(init)) | |
| { | |
| CDataObject *cd = (CDataObject *)init; | |
| if (cd->c_type == ct) | |
| { | |
| Py_ssize_t n = get_array_length(cd); | |
| memcpy(data, cd->c_data, n * ctitem->ct_size); | |
| return 0; | |
| } | |
| } | |
| return _convert_error(init, ct, expected); | |
| } | |
| static int | |
| convert_struct_from_object(char *data, CTypeDescrObject *ct, PyObject *init, | |
| Py_ssize_t *optvarsize) | |
| { | |
| /* does not accept 'init' being already a CData */ | |
| const char *expected; | |
| if (force_lazy_struct(ct) <= 0) { | |
| if (!PyErr_Occurred()) | |
| PyErr_Format(PyExc_TypeError, "'%s' is opaque", ct->ct_name); | |
| 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; i<n; i++) { | |
| while (cf != NULL && (cf->cf_flags & BF_IGNORE_IN_CTOR)) | |
| cf = cf->cf_next; | |
| if (cf == NULL) { | |
| PyErr_Format(PyExc_ValueError, | |
| "too many initializers for '%s' (got %zd)", | |
| ct->ct_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, 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) { | |
| int combined_flags = ct->ct_flags | ctinit->ct_flags; | |
| if (combined_flags & CT_IS_VOID_PTR) | |
| ; /* accept "void *" as either source or target */ | |
| else if (combined_flags & CT_IS_VOIDCHAR_PTR) { | |
| /* for backward compatibility, accept "char *" as either | |
| source of target. This is not what C does, though, | |
| so emit a warning that will eventually turn into an | |
| error. The warning is turned off if both types are | |
| pointers to single bytes. */ | |
| char *msg = (ct->ct_flags & CT_IS_VOIDCHAR_PTR ? | |
| "implicit cast to 'char *' from a different pointer type: " | |
| "will be forbidden in the future (check that the types " | |
| "are as you expect; use an explicit ffi.cast() if they " | |
| "are correct)" : | |
| "implicit cast from 'char *' to a different pointer type: " | |
| "will be forbidden in the future (check that the types " | |
| "are as you expect; use an explicit ffi.cast() if they " | |
| "are correct)"); | |
| if ((ct->ct_flags & ctinit->ct_flags & CT_POINTER) && | |
| ct->ct_itemdescr->ct_size == 1 && | |
| ctinit->ct_itemdescr->ct_size == 1) { | |
| /* no warning */ | |
| } | |
| else if (PyErr_WarnEx(PyExc_UserWarning, msg, 1)) | |
| return -1; | |
| } | |
| 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 > 1ULL) /* value != 0 && value != 1 */ | |
| goto overflow; | |
| } | |
| else { | |
| 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) { | |
| switch (ct->ct_size) { | |
| case sizeof(char): { | |
| int res = _convert_to_char(init); | |
| if (res < 0) | |
| return -1; | |
| data[0] = res; | |
| return 0; | |
| } | |
| case 2: { | |
| cffi_char16_t res = _convert_to_char16_t(init); | |
| if (res == (cffi_char16_t)-1 && PyErr_Occurred()) | |
| return -1; | |
| *(cffi_char16_t *)data = res; | |
| return 0; | |
| } | |
| case 4: { | |
| cffi_char32_t res = _convert_to_char32_t(init); | |
| if (res == (cffi_char32_t)-1 && PyErr_Occurred()) | |
| return -1; | |
| *(cffi_char32_t *)data = res; | |
| return 0; | |
| } | |
| } | |
| } | |
| 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); | |
| } | |
| if (ct->ct_flags & CT_PRIMITIVE_COMPLEX) { | |
| Py_complex value = PyComplex_AsCComplex(init); | |
| if (PyErr_Occurred()) | |
| return -1; | |
| write_raw_complex_data(data, value, ct->ct_size); | |
| return 0; | |
| } | |
| 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, 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 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; | |
| if (align == -1 && (ct->ct_flags & CT_LAZY_FIELD_LIST)) { | |
| force_lazy_struct(ct); | |
| 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) { | |
| /* for ffi.new("struct *") */ | |
| 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) | |
| { | |
| PyObject_GC_UnTrack(cd); | |
| if (cd->c_type->ct_flags & CT_IS_VOID_PTR) { /* a handle */ | |
| PyObject *x = ((CDataObject_own_structptr *)cd)->structobj; | |
| Py_DECREF(x); | |
| } | |
| else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) { /* a callback */ | |
| ffi_closure *closure = ((CDataObject_closure *)cd)->closure; | |
| PyObject *args = (PyObject *)(closure->user_data); | |
| Py_XDECREF(args); | |
| #if CFFI_CHECK_FFI_CLOSURE_ALLOC_MAYBE | |
| if (CFFI_CHECK_FFI_CLOSURE_ALLOC) { | |
| ffi_closure_free(closure); | |
| } else | |
| #endif | |
| cffi_closure_free(closure); | |
| } | |
| else { | |
| Py_FatalError("cdata CDataOwningGC_Type with unexpected type flags"); | |
| } | |
| cdata_dealloc(cd); | |
| } | |
| static void cdatafrombuf_dealloc(CDataObject *cd) | |
| { | |
| Py_buffer *view = ((CDataObject_frombuf *)cd)->bufferview; | |
| cdata_dealloc(cd); | |
| PyBuffer_Release(view); | |
| PyObject_Free(view); | |
| } | |
| static int cdataowninggc_traverse(CDataObject *cd, visitproc visit, void *arg) | |
| { | |
| if (cd->c_type->ct_flags & CT_IS_VOID_PTR) { /* a handle */ | |
| PyObject *x = ((CDataObject_own_structptr *)cd)->structobj; | |
| Py_VISIT(x); | |
| } | |
| else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) { /* a callback */ | |
| ffi_closure *closure = ((CDataObject_closure *)cd)->closure; | |
| PyObject *args = (PyObject *)(closure->user_data); | |
| Py_VISIT(args); | |
| } | |
| return 0; | |
| } | |
| static int cdatafrombuf_traverse(CDataObject *cd, visitproc visit, void *arg) | |
| { | |
| Py_buffer *view = ((CDataObject_frombuf *)cd)->bufferview; | |
| Py_VISIT(view->obj); | |
| return 0; | |
| } | |
| static int cdataowninggc_clear(CDataObject *cd) | |
| { | |
| if (cd->c_type->ct_flags & CT_IS_VOID_PTR) { /* a handle */ | |
| CDataObject_own_structptr *cd1 = (CDataObject_own_structptr *)cd; | |
| PyObject *x = cd1->structobj; | |
| Py_INCREF(Py_None); | |
| cd1->structobj = Py_None; | |
| Py_DECREF(x); | |
| } | |
| else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) { /* a callback */ | |
| ffi_closure *closure = ((CDataObject_closure *)cd)->closure; | |
| PyObject *args = (PyObject *)(closure->user_data); | |
| closure->user_data = NULL; | |
| Py_XDECREF(args); | |
| } | |
| return 0; | |
| } | |
| static int cdatafrombuf_clear(CDataObject *cd) | |
| { | |
| Py_buffer *view = ((CDataObject_frombuf *)cd)->bufferview; | |
| PyBuffer_Release(view); | |
| return 0; | |
| } | |
| /* forward */ | |
| static void _my_PyErr_WriteUnraisable(PyObject *t, PyObject *v, PyObject *tb, | |
| char *objdescr, PyObject *obj, | |
| char *extra_error_line); | |
| static void gcp_finalize(PyObject *destructor, PyObject *origobj) | |
| { | |
| /* NOTE: this decrements the reference count of the two arguments */ | |
| if (destructor != NULL) { | |
| PyObject *result; | |
| PyObject *error_type, *error_value, *error_traceback; | |
| /* Save the current exception */ | |
| PyErr_Fetch(&error_type, &error_value, &error_traceback); | |
| result = PyObject_CallFunctionObjArgs(destructor, origobj, NULL); | |
| if (result != NULL) { | |
| Py_DECREF(result); | |
| } | |
| else { | |
| PyObject *t, *v, *tb; | |
| PyErr_Fetch(&t, &v, &tb); | |
| /* Don't use error capture here, because it is very much | |
| * like errors at __del__(), and these ones are not captured | |
| * either */ | |
| /* ecap = _cffi_start_error_capture(); */ | |
| _my_PyErr_WriteUnraisable(t, v, tb, "From callback for ffi.gc ", | |
| origobj, NULL); | |
| /* _cffi_stop_error_capture(ecap); */ | |
| } | |
| Py_DECREF(destructor); | |
| /* Restore the saved exception */ | |
| PyErr_Restore(error_type, error_value, error_traceback); | |
| } | |
| Py_XDECREF(origobj); | |
| } | |
| static void cdatagcp_finalize(CDataObject_gcp *cd) | |
| { | |
| PyObject *destructor = cd->destructor; | |
| PyObject *origobj = cd->origobj; | |
| cd->destructor = NULL; | |
| cd->origobj = NULL; | |
| gcp_finalize(destructor, origobj); | |
| } | |
| static void cdatagcp_dealloc(CDataObject_gcp *cd) | |
| { | |
| PyObject *destructor = cd->destructor; | |
| PyObject *origobj = cd->origobj; | |
| cdata_dealloc((CDataObject *)cd); | |
| gcp_finalize(destructor, origobj); | |
| } | |
| static int cdatagcp_traverse(CDataObject_gcp *cd, visitproc visit, void *arg) | |
| { | |
| Py_VISIT(cd->destructor); | |
| Py_VISIT(cd->origobj); | |
| 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 "<cdata 'struct foo' 0x...>" because the | |
| struct foo is not owned. Trying to make it clearer, write in this | |
| case "<cdata 'struct foo &' 0x...>". */ | |
| if (cd->c_type->ct_flags & (CT_STRUCT|CT_UNION)) | |
| extra = " &"; | |
| else | |
| extra = ""; | |
| result = PyText_FromFormat("<cdata '%s%s' %s>", | |
| 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("<cdata '%s' %s %s>", | |
| cd->c_type->ct_name, text, PyText_AsUTF8(s)); | |
| Py_DECREF(s); | |
| return res; | |
| } | |
| static Py_ssize_t _cdata_var_byte_size(CDataObject *cd) | |
| { | |
| /* If 'cd' is a 'struct foo' or 'struct foo *' allocated with | |
| ffi.new(), and if the struct foo contains a varsize array, | |
| then return the real allocated size. Otherwise, return -1. */ | |
| if (!CDataOwn_Check(cd)) | |
| return -1; | |
| if (cd->c_type->ct_flags & CT_IS_PTR_TO_OWNED) { | |
| cd = (CDataObject *)((CDataObject_own_structptr *)cd)->structobj; | |
| } | |
| if (cd->c_type->ct_flags & CT_WITH_VAR_ARRAY) { | |
| return ((CDataObject_own_length *)cd)->length; | |
| } | |
| return -1; | |
| } | |
| static PyObject *_frombuf_repr(CDataObject *cd, const char *cd_type_name) | |
| { | |
| Py_buffer *view = ((CDataObject_frombuf *)cd)->bufferview; | |
| const char *obj_tp_name; | |
| if (view->obj == NULL) { | |
| return PyText_FromFormat( | |
| "<cdata '%s' buffer RELEASED>", | |
| cd_type_name); | |
| } | |
| obj_tp_name = Py_TYPE(view->obj)->tp_name; | |
| if (cd->c_type->ct_flags & CT_ARRAY) | |
| { | |
| Py_ssize_t buflen = get_array_length(cd); | |
| return PyText_FromFormat( | |
| "<cdata '%s' buffer len %zd from '%.200s' object>", | |
| cd_type_name, | |
| buflen, | |
| obj_tp_name); | |
| } | |
| else | |
| { | |
| return PyText_FromFormat( | |
| "<cdata '%s' buffer from '%.200s' object>", | |
| cd_type_name, | |
| obj_tp_name); | |
| } | |
| } | |
| static PyObject *cdataowning_repr(CDataObject *cd) | |
| { | |
| Py_ssize_t size = _cdata_var_byte_size(cd); | |
| if (size < 0) { | |
| if (cd->c_type->ct_flags & CT_POINTER) | |
| 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 | |
| size = cd->c_type->ct_size; | |
| } | |
| return PyText_FromFormat("<cdata '%s' owning %zd bytes>", | |
| cd->c_type->ct_name, size); | |
| } | |
| static PyObject *cdataowninggc_repr(CDataObject *cd) | |
| { | |
| if (cd->c_type->ct_flags & CT_IS_VOID_PTR) { /* a handle */ | |
| PyObject *x = ((CDataObject_own_structptr *)cd)->structobj; | |
| return _cdata_repr2(cd, "handle to", x); | |
| } | |
| else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) { /* a callback */ | |
| ffi_closure *closure = ((CDataObject_closure *)cd)->closure; | |
| PyObject *args = (PyObject *)closure->user_data; | |
| if (args == NULL) | |
| return cdata_repr(cd); | |
| else | |
| return _cdata_repr2(cd, "calling", PyTuple_GET_ITEM(args, 1)); | |
| } | |
| return cdataowning_repr(cd); /* but should be unreachable */ | |
| } | |
| static PyObject *cdatafrombuf_repr(CDataObject *cd) | |
| { | |
| return _frombuf_repr(cd, cd->c_type->ct_name); | |
| } | |
| static int cdata_nonzero(CDataObject *cd) | |
| { | |
| if (cd->c_type->ct_flags & CT_PRIMITIVE_ANY) { | |
| if (cd->c_type->ct_flags & (CT_PRIMITIVE_SIGNED | | |
| CT_PRIMITIVE_UNSIGNED | | |
| CT_PRIMITIVE_CHAR)) | |
| return read_raw_unsigned_data(cd->c_data, cd->c_type->ct_size) != 0; | |
| if (cd->c_type->ct_flags & CT_PRIMITIVE_FLOAT) { | |
| if (cd->c_type->ct_flags & CT_IS_LONGDOUBLE) | |
| return read_raw_longdouble_data(cd->c_data) != 0.0; | |
| return read_raw_float_data(cd->c_data, cd->c_type->ct_size) != 0.0; | |
| } | |
| if (cd->c_type->ct_flags & CT_PRIMITIVE_COMPLEX) { | |
| Py_complex value = read_raw_complex_data(cd->c_data, | |
| cd->c_type->ct_size); | |
| return value.real != 0.0 || value.imag != 0.0; | |
| } | |
| } | |
| 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)) { | |
| PyObject *result = convert_to_object(cd->c_data, cd->c_type); | |
| if (result != NULL && PyBool_Check(result)) | |
| result = PyInt_FromLong(PyInt_AsLong(result)); | |
| return result; | |
| } | |
| else if (cd->c_type->ct_flags & CT_PRIMITIVE_CHAR) { | |
| /*READ(cd->c_data, cd->c_type->ct_size)*/ | |
| switch (cd->c_type->ct_size) { | |
| case sizeof(char): | |
| return PyInt_FromLong((unsigned char)cd->c_data[0]); | |
| case 2: | |
| return PyInt_FromLong((long)*(cffi_char16_t *)cd->c_data); | |
| case 4: | |
| if (cd->c_type->ct_flags & CT_IS_SIGNED_WCHAR) | |
| return PyInt_FromLong((long)*(int32_t *)cd->c_data); | |
| else if (sizeof(long) > 4) | |
| return PyInt_FromLong(*(uint32_t *)cd->c_data); | |
| else | |
| return PyLong_FromUnsignedLong(*(uint32_t *)cd->c_data); | |
| } | |
| } | |
| 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 v_is_ptr, w_is_ptr; | |
| PyObject *pyres; | |
| assert(CData_Check(v)); | |
| /* Comparisons involving a primitive cdata work differently than | |
| * comparisons involving a struct/array/pointer. | |
| * | |
| * If v or w is a struct/array/pointer, then the other must be too | |
| * (otherwise we return NotImplemented and leave the case to | |
| * Python). If both are, then we compare the addresses. | |
| * | |
| * If v and/or w is a primitive cdata, then we convert the cdata(s) | |
| * to regular Python objects and redo the comparison there. | |
| */ | |
| v_is_ptr = !(((CDataObject *)v)->c_type->ct_flags & CT_PRIMITIVE_ANY); | |
| w_is_ptr = CData_Check(w) && | |
| !(((CDataObject *)w)->c_type->ct_flags & CT_PRIMITIVE_ANY); | |
| if (v_is_ptr && w_is_ptr) { | |
| int res; | |
| char *v_cdata = ((CDataObject *)v)->c_data; | |
| char *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; | |
| } | |
| else if (v_is_ptr || w_is_ptr) { | |
| pyres = Py_NotImplemented; | |
| } | |
| else { | |
| PyObject *aa[2]; | |
| int i; | |
| aa[0] = v; Py_INCREF(v); | |
| aa[1] = w; Py_INCREF(w); | |
| pyres = NULL; | |
| for (i = 0; i < 2; i++) { | |
| v = aa[i]; | |
| if (!CData_Check(v)) | |
| continue; | |
| w = convert_to_object(((CDataObject *)v)->c_data, | |
| ((CDataObject *)v)->c_type); | |
| if (w == NULL) | |
| goto error; | |
| if (CData_Check(w)) { | |
| Py_DECREF(w); | |
| PyErr_Format(PyExc_NotImplementedError, | |
| "cannot use <cdata '%s'> in a comparison", | |
| ((CDataObject *)v)->c_type->ct_name); | |
| goto error; | |
| } | |
| aa[i] = w; | |
| Py_DECREF(v); | |
| } | |
| pyres = PyObject_RichCompare(aa[0], aa[1], op); | |
| error: | |
| Py_DECREF(aa[1]); | |
| Py_DECREF(aa[0]); | |
| return pyres; | |
| } | |
| Py_INCREF(pyres); | |
| return pyres; | |
| } | |
| #if PY_MAJOR_VERSION < 3 | |
| typedef long Py_hash_t; | |
| #endif | |
| static Py_hash_t cdata_hash(PyObject *v) | |
| { | |
| if (((CDataObject *)v)->c_type->ct_flags & CT_PRIMITIVE_ANY) { | |
| PyObject *vv = convert_to_object(((CDataObject *)v)->c_data, | |
| ((CDataObject *)v)->c_type); | |
| if (vv == NULL) | |
| return -1; | |
| if (!CData_Check(vv)) { | |
| Py_hash_t hash = PyObject_Hash(vv); | |
| Py_DECREF(vv); | |
| return hash; | |
| } | |
| Py_DECREF(vv); | |
| } | |
| return _Py_HashPointer(((CDataObject *)v)->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)) { | |
| if (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_data == NULL) { | |
| PyErr_Format(PyExc_RuntimeError, | |
| "cannot dereference null pointer from cdata '%s'", | |
| 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"); | |
| 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, Py_ssize_t length); /* 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"); | |
| 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) | |
| { | |
| char *cdata; | |
| Py_ssize_t bounds[2]; | |
| CTypeDescrObject *ct = _cdata_getslicearg(cd, slice, bounds); | |
| if (ct == NULL) | |
| return NULL; | |
| if (ct->ct_stuff == NULL) { | |
| ct->ct_stuff = new_array_type(ct, -1); | |
| if (ct->ct_stuff == NULL) | |
| return NULL; | |
| } | |
| ct = (CTypeDescrObject *)ct->ct_stuff; | |
| cdata = cd->c_data + ct->ct_itemdescr->ct_size * bounds[0]; | |
| return new_sized_cdata(cdata, ct, bounds[1]); | |
| } | |
| 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 <char[]>[0:N] = b"somestring" or bytearray, which | |
| also adds support for Python 3: otherwise, you get integers while | |
| enumerating the string, and you can't set them to characters :-/ | |
| */ | |
| if ((ct->ct_flags & CT_PRIMITIVE_CHAR) && itemsize == sizeof(char)) { | |
| char *src; | |
| Py_ssize_t srclen; | |
| if (PyBytes_Check(v)) { | |
| srclen = PyBytes_GET_SIZE(v); | |
| src = PyBytes_AS_STRING(v); | |
| } | |
| else if (PyByteArray_Check(v)) { | |
| srclen = PyByteArray_GET_SIZE(v); | |
| src = PyByteArray_AS_STRING(v); | |
| } | |
| else | |
| goto other_types; | |
| if (srclen != length) { | |
| PyErr_Format(PyExc_ValueError, | |
| "need a string of length %zd, got %zd", | |
| length, srclen); | |
| return -1; | |
| } | |
| memcpy(cdata, src, length); | |
| return 0; | |
| } | |
| other_types: | |
| 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; | |
| diff = cdv->c_data - cdw->c_data; | |
| if (itemsize > 1) { | |
| if (diff % itemsize) { | |
| PyErr_SetString(PyExc_ValueError, | |
| "pointer subtraction: the distance between the two " | |
| "pointers is not a multiple of the item size"); | |
| return NULL; | |
| } | |
| diff = diff / 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 void | |
| _cdata_attr_errmsg(char *errmsg, CDataObject *cd, PyObject *attr) | |
| { | |
| const char *text; | |
| if (!PyErr_ExceptionMatches(PyExc_AttributeError)) | |
| return; | |
| PyErr_Clear(); | |
| text = PyText_AsUTF8(attr); | |
| if (text == NULL) | |
| return; | |
| PyErr_Format(PyExc_AttributeError, errmsg, cd->c_type->ct_name, text); | |
| } | |
| static PyObject * | |
| cdata_getattro(CDataObject *cd, PyObject *attr) | |
| { | |
| CFieldObject *cf; | |
| CTypeDescrObject *ct = cd->c_type; | |
| char *errmsg = "cdata '%s' has no attribute '%s'"; | |
| PyObject *x; | |
| if (ct->ct_flags & CT_POINTER) | |
| ct = ct->ct_itemdescr; | |
| if (ct->ct_flags & (CT_STRUCT|CT_UNION)) { | |
| switch (force_lazy_struct(ct)) { | |
| case 1: | |
| cf = (CFieldObject *)PyDict_GetItem(ct->ct_stuff, attr); | |
| if (cf != NULL) { | |
| /* read the field 'cf' */ | |
| char *data = cd->c_data + cf->cf_offset; | |
| Py_ssize_t array_len, size; | |
| if (cf->cf_bitshift == BS_REGULAR) { | |
| return convert_to_object(data, cf->cf_type); | |
| } | |
| else if (cf->cf_bitshift != BS_EMPTY_ARRAY) { | |
| return convert_to_object_bitfield(data, cf); | |
| } | |
| /* variable-length array: */ | |
| /* if reading variable length array from variable length | |
| struct, calculate array type from allocated length */ | |
| size = _cdata_var_byte_size(cd) - cf->cf_offset; | |
| if (size >= 0) { | |
| array_len = size / cf->cf_type->ct_itemdescr->ct_size; | |
| return new_sized_cdata(data, cf->cf_type, array_len); | |
| } | |
| return new_simple_cdata(data, | |
| (CTypeDescrObject *)cf->cf_type->ct_stuff); | |
| } | |
| errmsg = "cdata '%s' has no field '%s'"; | |
| break; | |
| case -1: | |
| return NULL; | |
| default: | |
| errmsg = "cdata '%s' points to an opaque type: cannot read fields"; | |
| break; | |
| } | |
| } | |
| x = PyObject_GenericGetAttr((PyObject *)cd, attr); | |
| if (x == NULL) | |
| _cdata_attr_errmsg(errmsg, cd, attr); | |
| return x; | |
| } | |
| static int | |
| cdata_setattro(CDataObject *cd, PyObject *attr, PyObject *value) | |
| { | |
| CFieldObject *cf; | |
| CTypeDescrObject *ct = cd->c_type; | |
| char *errmsg = "cdata '%s' has no attribute '%s'"; | |
| int x; | |
| if (ct->ct_flags & CT_POINTER) | |
| ct = ct->ct_itemdescr; | |
| if (ct->ct_flags & (CT_STRUCT|CT_UNION)) { | |
| switch (force_lazy_struct(ct)) { | |
| case 1: | |
| 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; | |
| } | |
| } | |
| errmsg = "cdata '%s' has no field '%s'"; | |
| break; | |
| case -1: | |
| return -1; | |
| default: | |
| errmsg = "cdata '%s' points to an opaque type: cannot write fields"; | |
| break; | |
| } | |
| } | |
| x = PyObject_GenericSetAttr((PyObject *)cd, attr, value); | |
| if (x < 0) | |
| _cdata_attr_errmsg(errmsg, cd, attr); | |
| return x; | |
| } | |
| static PyObject * | |
| convert_struct_to_owning_object(char *data, CTypeDescrObject *ct); /*forward*/ | |
| static cif_description_t * | |
| fb_prepare_cif(PyObject *fargs, CTypeDescrObject *, Py_ssize_t, ffi_abi); | |
| /*forward*/ | |
| static PyObject *new_primitive_type(const char *name); /*forward*/ | |
| static CTypeDescrObject *_get_ct_int(void) | |
| { | |
| static CTypeDescrObject *ct_int = NULL; | |
| if (ct_int == NULL) { | |
| ct_int = (CTypeDescrObject *)new_primitive_type("int"); | |
| } | |
| 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_IS_VOIDCHAR_PTR) || | |
| ((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); | |
| if (ctitem->ct_flags & CT_IS_BOOL) | |
| if (must_be_array_of_zero_or_one(*output_data, | |
| PyBytes_GET_SIZE(init)) < 0) | |
| return -1; | |
| 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 */ | |
| if (ctitem->ct_size == 2) | |
| length = _my_PyUnicode_SizeAsChar16(init); | |
| else | |
| length = _my_PyUnicode_SizeAsChar32(init); | |
| length += 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 = MUL_WRAPAROUND(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; | |
| struct freeme_s { | |
| struct freeme_s *next; | |
| union_alignment alignment; | |
| } *freeme = NULL; | |
| 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 (cd->c_data == NULL) { | |
| PyErr_Format(PyExc_RuntimeError, | |
| "cannot call null pointer pointer from cdata '%s'", | |
| 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 < (Py_ssize_t)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, nargs_declared, 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; i<nargs; i++) { | |
| CTypeDescrObject *argtype; | |
| char *data = buffer + cif_descr->exchange_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 { | |
| if (datasize <= 512) { | |
| tmpbuf = alloca(datasize); | |
| } | |
| else { | |
| struct freeme_s *fp = (struct freeme_s *)PyObject_Malloc( | |
| offsetof(struct freeme_s, alignment) + | |
| (size_t)datasize); | |
| if (fp == NULL) { | |
| PyErr_NoMemory(); | |
| goto error; | |
| } | |
| fp->next = freeme; | |
| freeme = fp; | |
| tmpbuf = (char *)&fp->alignment; | |
| } | |
| 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: | |
| while (freeme != NULL) { | |
| void *p = (void *)freeme; | |
| freeme = freeme->next; | |
| PyObject_Free(p); | |
| } | |
| 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_dir(PyObject *cd, PyObject *noarg) | |
| { | |
| CTypeDescrObject *ct = ((CDataObject *)cd)->c_type; | |
| /* replace the type 'pointer-to-t' with just 't' */ | |
| if (ct->ct_flags & CT_POINTER) { | |
| ct = ct->ct_itemdescr; | |
| } | |
| if ((ct->ct_flags & (CT_STRUCT | CT_UNION)) && | |
| !(ct->ct_flags & CT_IS_OPAQUE)) { | |
| /* for non-opaque structs or unions */ | |
| if (force_lazy_struct(ct) < 0) | |
| return NULL; | |
| return PyDict_Keys(ct->ct_stuff); | |
| } | |
| else { | |
| return PyList_New(0); /* empty list for the other cases */ | |
| } | |
| } | |
| static PyObject *cdata_complex(PyObject *cd_, PyObject *noarg) | |
| { | |
| CDataObject *cd = (CDataObject *)cd_; | |
| if (cd->c_type->ct_flags & CT_PRIMITIVE_COMPLEX) { | |
| Py_complex value = read_raw_complex_data(cd->c_data, cd->c_type->ct_size); | |
| PyObject *op = PyComplex_FromCComplex(value); | |
| return op; | |
| } | |
| /* <cdata 'float'> or <cdata 'int'> cannot be directly converted by | |
| calling complex(), just like <cdata 'int'> cannot be directly | |
| converted by calling float() */ | |
| PyErr_Format(PyExc_TypeError, "complex() not supported on cdata '%s'", | |
| cd->c_type->ct_name); | |
| return NULL; | |
| } | |
| static int explicit_release_case(PyObject *cd) | |
| { | |
| CTypeDescrObject *ct = ((CDataObject *)cd)->c_type; | |
| if (Py_TYPE(cd) == &CDataOwning_Type) { | |
| if ((ct->ct_flags & (CT_POINTER | CT_ARRAY)) != 0) /* ffi.new() */ | |
| return 0; | |
| } | |
| else if (Py_TYPE(cd) == &CDataFromBuf_Type) { | |
| return 1; /* ffi.from_buffer() */ | |
| } | |
| else if (Py_TYPE(cd) == &CDataGCP_Type) { | |
| return 2; /* ffi.gc() */ | |
| } | |
| PyErr_SetString(PyExc_ValueError, | |
| "only 'cdata' object from ffi.new(), ffi.gc(), ffi.from_buffer() " | |
| "or ffi.new_allocator()() can be used with the 'with' keyword or " | |
| "ffi.release()"); | |
| return -1; | |
| } | |
| static PyObject *cdata_enter(PyObject *cd, PyObject *noarg) | |
| { | |
| if (explicit_release_case(cd) < 0) /* only to check the ctype */ | |
| return NULL; | |
| Py_INCREF(cd); | |
| return cd; | |
| } | |
| static PyObject *cdata_exit(PyObject *cd, PyObject *args) | |
| { | |
| /* 'args' ignored */ | |
| CTypeDescrObject *ct; | |
| Py_buffer *view; | |
| switch (explicit_release_case(cd)) | |
| { | |
| case 0: /* ffi.new() */ | |
| /* no effect on CPython: raw memory is allocated with the | |
| same malloc() as the object itself, so it can't be | |
| released independently. If we use a custom allocator, | |
| then it's implemented with ffi.gc(). */ | |
| ct = ((CDataObject *)cd)->c_type; | |
| if (ct->ct_flags & CT_IS_PTR_TO_OWNED) { | |
| PyObject *x = ((CDataObject_own_structptr *)cd)->structobj; | |
| if (Py_TYPE(x) == &CDataGCP_Type) { | |
| /* this is a special case for | |
| ffi.new_allocator()("struct-or-union *") */ | |
| cdatagcp_finalize((CDataObject_gcp *)x); | |
| } | |
| } | |
| break; | |
| case 1: /* ffi.from_buffer() */ | |
| view = ((CDataObject_frombuf *)cd)->bufferview; | |
| PyBuffer_Release(view); | |
| break; | |
| case 2: /* ffi.gc() or ffi.new_allocator()("not-struct-nor-union") */ | |
| /* call the destructor immediately */ | |
| cdatagcp_finalize((CDataObject_gcp *)cd); | |
| break; | |
| default: | |
| return NULL; | |
| } | |
| Py_INCREF(Py_None); | |
| return Py_None; | |
| } | |
| 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 PyMethodDef cdata_methods[] = { | |
| {"__dir__", cdata_dir, METH_NOARGS}, | |
| {"__complex__", cdata_complex, METH_NOARGS}, | |
| {"__enter__", cdata_enter, METH_NOARGS}, | |
| {"__exit__", cdata_exit, METH_VARARGS}, | |
| {NULL, NULL} /* sentinel */ | |
| }; | |
| static PyTypeObject CData_Type = { | |
| PyVarObject_HEAD_INIT(NULL, 0) | |
| "_cffi_backend._CDataBase", | |
| 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 */ | |
| 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 */ | |
| "The internal base type for CData objects. Use FFI.CData to access " | |
| "it. Always check with isinstance(): subtypes are sometimes returned " | |
| "on CPython, for performance reasons.", /* 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 */ | |
| cdata_methods, /* tp_methods */ | |
| 0, /* tp_members */ | |
| 0, /* tp_getset */ | |
| 0, /* tp_base */ | |
| 0, /* tp_dict */ | |
| 0, /* tp_descr_get */ | |
| 0, /* tp_descr_set */ | |
| 0, /* tp_dictoffset */ | |
| 0, /* tp_init */ | |
| 0, /* tp_alloc */ | |
| 0, /* tp_new */ | |
| PyObject_Del, /* tp_free */ | |
| }; | |
| 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, /* inherited */ /* tp_as_number */ | |
| 0, /* tp_as_sequence */ | |
| &CDataOwn_as_mapping, /* tp_as_mapping */ | |
| 0, /* inherited */ /* tp_hash */ | |
| 0, /* inherited */ /* tp_call */ | |
| 0, /* tp_str */ | |
| 0, /* inherited */ /* tp_getattro */ | |
| 0, /* inherited */ /* tp_setattro */ | |
| 0, /* tp_as_buffer */ | |
| Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /* tp_flags */ | |
| "This is an internal subtype of _CDataBase for performance only on " | |
| "CPython. Check with isinstance(x, ffi.CData).", /* tp_doc */ | |
| 0, /* tp_traverse */ | |
| 0, /* tp_clear */ | |
| 0, /* inherited */ /* tp_richcompare */ | |
| 0, /* inherited */ /* tp_weaklistoffset */ | |
| 0, /* inherited */ /* tp_iter */ | |
| 0, /* tp_iternext */ | |
| 0, /* inherited */ /* tp_methods */ | |
| 0, /* tp_members */ | |
| 0, /* tp_getset */ | |
| &CData_Type, /* tp_base */ | |
| 0, /* tp_dict */ | |
| 0, /* tp_descr_get */ | |
| 0, /* tp_descr_set */ | |
| 0, /* tp_dictoffset */ | |
| 0, /* tp_init */ | |
| 0, /* tp_alloc */ | |
| 0, /* tp_new */ | |
| free, /* tp_free */ | |
| }; | |
| static PyTypeObject CDataOwningGC_Type = { | |
| PyVarObject_HEAD_INIT(NULL, 0) | |
| "_cffi_backend.__CDataOwnGC", | |
| sizeof(CDataObject_own_structptr), | |
| 0, | |
| (destructor)cdataowninggc_dealloc, /* tp_dealloc */ | |
| 0, /* tp_print */ | |
| 0, /* tp_getattr */ | |
| 0, /* tp_setattr */ | |
| 0, /* tp_compare */ | |
| (reprfunc)cdataowninggc_repr, /* tp_repr */ | |
| 0, /* inherited */ /* tp_as_number */ | |
| 0, /* tp_as_sequence */ | |
| 0, /* inherited */ /* tp_as_mapping */ | |
| 0, /* inherited */ /* tp_hash */ | |
| 0, /* inherited */ /* tp_call */ | |
| 0, /* tp_str */ | |
| 0, /* inherited */ /* tp_getattro */ | |
| 0, /* inherited */ /* tp_setattro */ | |
| 0, /* tp_as_buffer */ | |
| Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES /* tp_flags */ | |
| | Py_TPFLAGS_HAVE_GC, | |
| "This is an internal subtype of _CDataBase for performance only on " | |
| "CPython. Check with isinstance(x, ffi.CData).", /* tp_doc */ | |
| (traverseproc)cdataowninggc_traverse, /* tp_traverse */ | |
| (inquiry)cdataowninggc_clear, /* tp_clear */ | |
| 0, /* inherited */ /* tp_richcompare */ | |
| 0, /* inherited */ /* tp_weaklistoffset */ | |
| 0, /* inherited */ /* tp_iter */ | |
| 0, /* tp_iternext */ | |
| 0, /* inherited */ /* tp_methods */ | |
| 0, /* tp_members */ | |
| 0, /* tp_getset */ | |
| &CDataOwning_Type, /* tp_base */ | |
| 0, /* tp_dict */ | |
| 0, /* tp_descr_get */ | |
| 0, /* tp_descr_set */ | |
| 0, /* tp_dictoffset */ | |
| 0, /* tp_init */ | |
| 0, /* tp_alloc */ | |
| 0, /* tp_new */ | |
| PyObject_GC_Del, /* tp_free */ | |
| }; | |
| static PyTypeObject CDataFromBuf_Type = { | |
| PyVarObject_HEAD_INIT(NULL, 0) | |
| "_cffi_backend.__CDataFromBuf", | |
| sizeof(CDataObject_frombuf), | |
| 0, | |
| (destructor)cdatafrombuf_dealloc, /* tp_dealloc */ | |
| 0, /* tp_print */ | |
| 0, /* tp_getattr */ | |
| 0, /* tp_setattr */ | |
| 0, /* tp_compare */ | |
| (reprfunc)cdatafrombuf_repr, /* tp_repr */ | |
| 0, /* inherited */ /* tp_as_number */ | |
| 0, /* tp_as_sequence */ | |
| 0, /* inherited */ /* tp_as_mapping */ | |
| 0, /* inherited */ /* tp_hash */ | |
| 0, /* inherited */ /* tp_call */ | |
| 0, /* tp_str */ | |
| 0, /* inherited */ /* tp_getattro */ | |
| 0, /* inherited */ /* tp_setattro */ | |
| 0, /* tp_as_buffer */ | |
| Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES /* tp_flags */ | |
| | Py_TPFLAGS_HAVE_GC, | |
| "This is an internal subtype of _CDataBase for performance only on " | |
| "CPython. Check with isinstance(x, ffi.CData).", /* tp_doc */ | |
| (traverseproc)cdatafrombuf_traverse, /* tp_traverse */ | |
| (inquiry)cdatafrombuf_clear, /* tp_clear */ | |
| 0, /* inherited */ /* tp_richcompare */ | |
| 0, /* inherited */ /* tp_weaklistoffset */ | |
| 0, /* inherited */ /* tp_iter */ | |
| 0, /* tp_iternext */ | |
| 0, /* inherited */ /* tp_methods */ | |
| 0, /* tp_members */ | |
| 0, /* tp_getset */ | |
| &CData_Type, /* tp_base */ | |
| 0, /* tp_dict */ | |
| 0, /* tp_descr_get */ | |
| 0, /* tp_descr_set */ | |
| 0, /* tp_dictoffset */ | |
| 0, /* tp_init */ | |
| 0, /* tp_alloc */ | |
| 0, /* tp_new */ | |
| PyObject_GC_Del, /* tp_free */ | |
| }; | |
| static PyTypeObject CDataGCP_Type = { | |
| PyVarObject_HEAD_INIT(NULL, 0) | |
| "_cffi_backend.__CDataGCP", | |
| sizeof(CDataObject_gcp), | |
| 0, | |
| (destructor)cdatagcp_dealloc, /* tp_dealloc */ | |
| 0, /* tp_print */ | |
| 0, /* tp_getattr */ | |
| 0, /* tp_setattr */ | |
| 0, /* tp_compare */ | |
| 0, /* inherited */ /* tp_repr */ | |
| 0, /* inherited */ /* tp_as_number */ | |
| 0, /* tp_as_sequence */ | |
| 0, /* inherited */ /* tp_as_mapping */ | |
| 0, /* inherited */ /* tp_hash */ | |
| 0, /* inherited */ /* tp_call */ | |
| 0, /* tp_str */ | |
| 0, /* inherited */ /* tp_getattro */ | |
| 0, /* inherited */ /* tp_setattro */ | |
| 0, /* tp_as_buffer */ | |
| Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES /* tp_flags */ | |
| #ifdef Py_TPFLAGS_HAVE_FINALIZE | |
| | Py_TPFLAGS_HAVE_FINALIZE | |
| #endif | |
| | Py_TPFLAGS_HAVE_GC, | |
| "This is an internal subtype of _CDataBase for performance only on " | |
| "CPython. Check with isinstance(x, ffi.CData).", /* tp_doc */ | |
| (traverseproc)cdatagcp_traverse, /* tp_traverse */ | |
| 0, /* tp_clear */ | |
| 0, /* inherited */ /* tp_richcompare */ | |
| 0, /* inherited */ /* tp_weaklistoffset */ | |
| 0, /* inherited */ /* tp_iter */ | |
| 0, /* tp_iternext */ | |
| 0, /* inherited */ /* tp_methods */ | |
| 0, /* tp_members */ | |
| 0, /* tp_getset */ | |
| &CData_Type, /* tp_base */ | |
| #ifdef Py_TPFLAGS_HAVE_FINALIZE /* CPython >= 3.4 */ | |
| 0, /* tp_dict */ | |
| 0, /* tp_descr_get */ | |
| 0, /* tp_descr_set */ | |
| 0, /* tp_dictoffset */ | |
| 0, /* tp_init */ | |
| 0, /* tp_alloc */ | |
| 0, /* tp_new */ | |
| 0, /* inherited */ /* tp_free */ | |
| 0, /* tp_is_gc */ | |
| 0, /* tp_bases */ | |
| 0, /* tp_mro */ | |
| 0, /* tp_cache */ | |
| 0, /* tp_subclasses */ | |
| 0, /* tp_weaklist */ | |
| 0, /* tp_del */ | |
| 0, /* version_tag */ | |
| (destructor)cdatagcp_finalize, /* tp_finalize */ | |
| #endif | |
| }; | |
| /************************************************************/ | |
| 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.__CData_iterator", /* 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, | |
| int dont_clear) | |
| { | |
| /* note: objects with &CDataOwning_Type are always allocated with | |
| either a plain malloc() or calloc(), and freed with free(). */ | |
| CDataObject *cd; | |
| if (dont_clear) | |
| cd = malloc(size); | |
| else | |
| cd = calloc(size, 1); | |
| 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) | |
| { | |
| /* also accepts unions, for the API mode */ | |
| CDataObject *cd; | |
| Py_ssize_t dataoffset = offsetof(CDataObject_own_nolength, alignment); | |
| Py_ssize_t datasize = ct->ct_size; | |
| if (datasize < 0) { | |
| PyErr_SetString(PyExc_TypeError, | |
| "return type is an opaque structure or union"); | |
| return NULL; | |
| } | |
| if (ct->ct_flags & CT_WITH_VAR_ARRAY) { | |
| PyErr_SetString(PyExc_TypeError, | |
| "return type is a struct/union with a varsize array member"); | |
| return NULL; | |
| } | |
| cd = allocate_owning_object(dataoffset + datasize, ct, /*dont_clear=*/1); | |
| if (cd == NULL) | |
| return NULL; | |
| cd->c_data = ((char *)cd) + dataoffset; | |
| memcpy(cd->c_data, data, datasize); | |
| return (PyObject *)cd; | |
| } | |
| static CDataObject *allocate_gcp_object(CDataObject *origobj, | |
| CTypeDescrObject *ct, | |
| PyObject *destructor) | |
| { | |
| CDataObject_gcp *cd = PyObject_GC_New(CDataObject_gcp, &CDataGCP_Type); | |
| if (cd == NULL) | |
| return NULL; | |
| Py_XINCREF(destructor); | |
| Py_INCREF(origobj); | |
| Py_INCREF(ct); | |
| cd->head.c_data = origobj->c_data; | |
| cd->head.c_type = ct; | |
| cd->head.c_weakreflist = NULL; | |
| cd->origobj = (PyObject *)origobj; | |
| cd->destructor = destructor; | |
| PyObject_GC_Track(cd); | |
| return (CDataObject *)cd; | |
| } | |
| static CDataObject *allocate_with_allocator(Py_ssize_t basesize, | |
| Py_ssize_t datasize, | |
| CTypeDescrObject *ct, | |
| const cffi_allocator_t *allocator) | |
| { | |
| CDataObject *cd; | |
| if (allocator->ca_alloc == NULL) { | |
| cd = allocate_owning_object(basesize + datasize, ct, | |
| allocator->ca_dont_clear); | |
| if (cd == NULL) | |
| return NULL; | |
| cd->c_data = ((char *)cd) + basesize; | |
| } | |
| else { | |
| PyObject *res = PyObject_CallFunction(allocator->ca_alloc, "n", datasize); | |
| if (res == NULL) | |
| return NULL; | |
| if (!CData_Check(res)) { | |
| PyErr_Format(PyExc_TypeError, | |
| "alloc() must return a cdata object (got %.200s)", | |
| Py_TYPE(res)->tp_name); | |
| Py_DECREF(res); | |
| return NULL; | |
| } | |
| cd = (CDataObject *)res; | |
| if (!(cd->c_type->ct_flags & (CT_POINTER|CT_ARRAY))) { | |
| PyErr_Format(PyExc_TypeError, | |
| "alloc() must return a cdata pointer, not '%s'", | |
| cd->c_type->ct_name); | |
| Py_DECREF(res); | |
| return NULL; | |
| } | |
| if (!cd->c_data) { | |
| PyErr_SetString(PyExc_MemoryError, "alloc() returned NULL"); | |
| Py_DECREF(res); | |
| return NULL; | |
| } | |
| cd = allocate_gcp_object(cd, ct, allocator->ca_free); | |
| Py_DECREF(res); | |
| if (!allocator->ca_dont_clear) | |
| memset(cd->c_data, 0, datasize); | |
| } | |
| return cd; | |
| } | |
| static PyObject *direct_newp(CTypeDescrObject *ct, PyObject *init, | |
| const cffi_allocator_t *allocator) | |
| { | |
| CTypeDescrObject *ctitem; | |
| CDataObject *cd; | |
| Py_ssize_t dataoffset, datasize, explicitlength; | |
| 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_STRUCT | CT_UNION)) { | |
| if (force_lazy_struct(ctitem) < 0) /* for CT_WITH_VAR_ARRAY */ | |
| return NULL; | |
| if (ctitem->ct_flags & CT_WITH_VAR_ARRAY) { | |
| assert(ct->ct_flags & CT_IS_PTR_TO_OWNED); | |
| dataoffset = offsetof(CDataObject_own_length, alignment); | |
| if (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(ct->ct_itemdescr, &init); | |
| if (explicitlength < 0) | |
| return NULL; | |
| ctitem = ct->ct_itemdescr; | |
| dataoffset = offsetof(CDataObject_own_length, alignment); | |
| datasize = MUL_WRAPAROUND(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_with_allocator(dataoffset, datasize, ct->ct_itemdescr, | |
| allocator); | |
| if (cds == NULL) | |
| return NULL; | |
| cd = allocate_owning_object(sizeof(CDataObject_own_structptr), ct, | |
| /*dont_clear=*/1); | |
| if (cd == NULL) { | |
| Py_DECREF(cds); | |
| return NULL; | |
| } | |
| /* store the only reference to cds into cd */ | |
| ((CDataObject_own_structptr *)cd)->structobj = (PyObject *)cds; | |
| /* store information about the allocated size of the struct */ | |
| if (dataoffset == offsetof(CDataObject_own_length, alignment)) { | |
| ((CDataObject_own_length *)cds)->length = datasize; | |
| } | |
| assert(explicitlength < 0); | |
| cd->c_data = cds->c_data; | |
| } | |
| else { | |
| cd = allocate_with_allocator(dataoffset, datasize, ct, allocator); | |
| if (cd == NULL) | |
| return NULL; | |
| if (explicitlength >= 0) | |
| ((CDataObject_own_length*)cd)->length = explicitlength; | |
| } | |
| 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 PyObject *b_newp(PyObject *self, PyObject *args) | |
| { | |
| CTypeDescrObject *ct; | |
| PyObject *init = Py_None; | |
| if (!PyArg_ParseTuple(args, "O!|O:newp", &CTypeDescr_Type, &ct, &init)) | |
| return NULL; | |
| return direct_newp(ct, init, &default_allocator); | |
| } | |
| 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 | |
| else if (PyUnicode_Check(ob)) { | |
| char err_buf[80]; | |
| cffi_char32_t ordinal; | |
| if (_my_PyUnicode_AsSingleChar32(ob, &ordinal, err_buf) < 0) { | |
| PyErr_Format(PyExc_TypeError, | |
| "cannot cast %s to ctype '%s'", err_buf, ct->ct_name); | |
| return NULL; | |
| } | |
| /* the types char16_t and char32_t are both unsigned. However, | |
| wchar_t might be signed. In theory it does not matter, | |
| because 'ordinal' comes from a regular Python unicode. */ | |
| #ifdef HAVE_WCHAR_H | |
| if (ct->ct_flags & CT_IS_SIGNED_WCHAR) | |
| value = (wchar_t)ordinal; | |
| else | |
| #endif | |
| value = ordinal; | |
| } | |
| 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; | |
| } | |
| /* returns -1 if cannot cast, 0 if we don't get a value, 1 if we do */ | |
| static int check_bytes_for_float_compatible(PyObject *io, double *out_value) | |
| { | |
| if (PyBytes_Check(io)) { | |
| if (PyBytes_GET_SIZE(io) != 1) | |
| goto error; | |
| *out_value = (unsigned char)PyBytes_AS_STRING(io)[0]; | |
| return 1; | |
| } | |
| else if (PyUnicode_Check(io)) { | |
| char ignored[80]; | |
| cffi_char32_t ordinal; | |
| if (_my_PyUnicode_AsSingleChar32(io, &ordinal, ignored) < 0) | |
| goto error; | |
| /* the signness of the 32-bit version of wide chars should not | |
| * matter here, because 'ordinal' comes from a normal Python | |
| * unicode string */ | |
| *out_value = ordinal; | |
| return 1; | |
| } | |
| *out_value = 0; /* silence a gcc warning if this function is inlined */ | |
| return 0; | |
| error: | |
| Py_DECREF(io); | |
| *out_value = 0; /* silence a gcc warning if this function is inlined */ | |
| return -1; | |
| } | |
| static PyObject *do_cast(CTypeDescrObject *ct, PyObject *ob) | |
| { | |
| CDataObject *cd; | |
| 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 | |
| <cdata 'int[3]'> 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; | |
| int res; | |
| 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); | |
| } | |
| res = check_bytes_for_float_compatible(io, &value); | |
| if (res == -1) | |
| goto cannot_cast; | |
| if (res == 0) { | |
| 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; | |
| } | |
| 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 if (ct->ct_flags & CT_PRIMITIVE_COMPLEX) { | |
| /* cast to a complex */ | |
| Py_complex value; | |
| PyObject *io; | |
| int res; | |
| 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); | |
| } | |
| res = check_bytes_for_float_compatible(io, &value.real); | |
| if (res == -1) | |
| goto cannot_cast; | |
| if (res == 1) { | |
| // got it from string | |
| value.imag = 0.0; | |
| } else { | |
| value = PyComplex_AsCComplex(io); | |
| } | |
| Py_DECREF(io); | |
| if (PyErr_Occurred()) { | |
| return NULL; | |
| } | |
| cd = _new_casted_primitive(ct); | |
| if (cd != NULL) { | |
| write_raw_complex_data(cd->c_data, value, ct->ct_size); | |
| } | |
| 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; | |
| } | |
| static PyObject *b_cast(PyObject *self, PyObject *args) | |
| { | |
| CTypeDescrObject *ct; | |
| PyObject *ob; | |
| if (!PyArg_ParseTuple(args, "O!O:cast", &CTypeDescr_Type, &ct, &ob)) | |
| return NULL; | |
| return do_cast(ct, ob); | |
| } | |
| /************************************************************/ | |
| typedef struct { | |
| PyObject_HEAD | |
| void *dl_handle; | |
| char *dl_name; | |
| int dl_auto_close; | |
| } DynLibObject; | |
| static void dl_dealloc(DynLibObject *dlobj) | |
| { | |
| if (dlobj->dl_handle != NULL && dlobj->dl_auto_close) | |
| dlclose(dlobj->dl_handle); | |
| free(dlobj->dl_name); | |
| PyObject_Del(dlobj); | |
| } | |
| static PyObject *dl_repr(DynLibObject *dlobj) | |
| { | |
| return PyText_FromFormat("<clibrary '%s'>", dlobj->dl_name); | |
| } | |
| static int dl_check_closed(DynLibObject *dlobj) | |
| { | |
| if (dlobj->dl_handle == NULL) | |
| { | |
| PyErr_Format(PyExc_ValueError, "library '%s' has already been closed", | |
| dlobj->dl_name); | |
| return -1; | |
| } | |
| return 0; | |
| } | |
| static PyObject *dl_load_function(DynLibObject *dlobj, PyObject *args) | |
| { | |
| CTypeDescrObject *ct; | |
| char *funcname; | |
| void *funcptr; | |
| if (!PyArg_ParseTuple(args, "O!s:load_function", | |
| &CTypeDescr_Type, &ct, &funcname)) | |
| return NULL; | |
| if (dl_check_closed(dlobj) < 0) | |
| return NULL; | |
| if (!(ct->ct_flags & (CT_FUNCTIONPTR | CT_POINTER | CT_ARRAY))) { | |
| PyErr_Format(PyExc_TypeError, | |
| "function or pointer or array 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_AttributeError, | |
| "function/symbol '%s' not found in library '%s': %s", | |
| funcname, dlobj->dl_name, error); | |
| return NULL; | |
| } | |
| if ((ct->ct_flags & CT_ARRAY) && ct->ct_length < 0) { | |
| ct = (CTypeDescrObject *)ct->ct_stuff; | |
| } | |
| 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; | |
| if (dl_check_closed(dlobj) < 0) | |
| 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; | |
| if (dl_check_closed(dlobj) < 0) | |
| 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 PyObject *dl_close_lib(DynLibObject *dlobj, PyObject *no_args) | |
| { | |
| if (dlobj->dl_handle != NULL) | |
| { | |
| dlclose(dlobj->dl_handle); | |
| dlobj->dl_handle = 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}, | |
| {"close_lib", (PyCFunction)dl_close_lib, METH_NOARGS}, | |
| {NULL, NULL} /* sentinel */ | |
| }; | |
| static PyTypeObject dl_type = { | |
| PyVarObject_HEAD_INIT(NULL, 0) | |
| "_cffi_backend.CLibrary", /* 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 void *b_do_dlopen(PyObject *args, const char **p_printable_filename, | |
| PyObject **p_temp, int *auto_close) | |
| { | |
| /* Logic to call the correct version of dlopen(). Returns NULL in case of error. | |
| Otherwise, '*p_printable_filename' will point to a printable char version of | |
| the filename (maybe utf-8-encoded). '*p_temp' will be set either to NULL or | |
| to a temporary object that must be freed after looking at printable_filename. | |
| */ | |
| void *handle; | |
| char *filename_or_null; | |
| int flags = 0; | |
| *p_temp = NULL; | |
| *auto_close = 1; | |
| 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; | |
| *p_printable_filename = "<None>"; | |
| } | |
| else if (CData_Check(PyTuple_GET_ITEM(args, 0))) | |
| { | |
| CDataObject *cd; | |
| if (!PyArg_ParseTuple(args, "O|i:load_library", &cd, &flags)) | |
| return NULL; | |
| /* 'flags' is accepted but ignored in this case */ | |
| if ((cd->c_type->ct_flags & CT_IS_VOID_PTR) == 0) { | |
| PyErr_Format(PyExc_TypeError, | |
| "dlopen() takes a file name or 'void *' handle, not '%s'", | |
| cd->c_type->ct_name); | |
| return NULL; | |
| } | |
| handle = cd->c_data; | |
| if (handle == NULL) { | |
| PyErr_Format(PyExc_RuntimeError, "cannot call dlopen(NULL)"); | |
| return NULL; | |
| } | |
| *p_temp = PyText_FromFormat("%p", handle); | |
| *p_printable_filename = PyText_AsUTF8(*p_temp); | |
| *auto_close = 0; | |
| return handle; | |
| } | |
| else | |
| { | |
| PyObject *s = PyTuple_GET_ITEM(args, 0); | |
| #ifdef MS_WIN32 | |
| PyObject *filename_unicode; | |
| if (PyArg_ParseTuple(args, "U|i:load_library", &filename_unicode, &flags)) | |
| { | |
| Py_ssize_t sz1; | |
| wchar_t *w1; | |
| #if PY_MAJOR_VERSION < 3 | |
| s = PyUnicode_AsUTF8String(s); | |
| if (s == NULL) | |
| return NULL; | |
| *p_temp = s; | |
| #endif | |
| *p_printable_filename = PyText_AsUTF8(s); | |
| if (*p_printable_filename == NULL) | |
| return NULL; | |
| sz1 = PyUnicode_GetSize(filename_unicode) + 1; | |
| sz1 *= 2; /* should not be needed, but you never know */ | |
| w1 = alloca(sizeof(wchar_t) * sz1); | |
| sz1 = PyUnicode_AsWideChar((PyUnicodeObject *)filename_unicode, | |
| w1, sz1 - 1); | |
| if (sz1 < 0) | |
| return NULL; | |
| w1[sz1] = 0; | |
| handle = dlopenW(w1); | |
| goto got_handle; | |
| } | |
| PyErr_Clear(); | |
| #endif | |
| if (!PyArg_ParseTuple(args, "et|i:load_library", | |
| Py_FileSystemDefaultEncoding, &filename_or_null, &flags)) | |
| return NULL; | |
| #if PY_MAJOR_VERSION < 3 | |
| if (PyUnicode_Check(s)) | |
| { | |
| s = PyUnicode_AsUTF8String(s); | |
| if (s == NULL) { | |
| PyMem_Free(filename_or_null); | |
| return NULL; | |
| } | |
| *p_temp = s; | |
| } | |
| #endif | |
| *p_printable_filename = PyText_AsUTF8(s); | |
| if (*p_printable_filename == NULL) { | |
| PyMem_Free(filename_or_null); | |
| return NULL; | |
| } | |
| } | |
| if ((flags & (RTLD_NOW | RTLD_LAZY)) == 0) | |
| flags |= RTLD_NOW; | |
| #ifdef MS_WIN32 | |
| if (filename_or_null == NULL) { | |
| PyErr_SetString(PyExc_OSError, "dlopen(None) not supported on Windows"); | |
| return NULL; | |
| } | |
| #endif | |
| handle = dlopen(filename_or_null, flags); | |
| PyMem_Free(filename_or_null); | |
| #ifdef MS_WIN32 | |
| got_handle: | |
| #endif | |
| if (handle == NULL) { | |
| const char *error = dlerror(); | |
| PyErr_Format(PyExc_OSError, "cannot load library '%s': %s", | |
| *p_printable_filename, error); | |
| return NULL; | |
| } | |
| return handle; | |
| } | |
| static PyObject *b_load_library(PyObject *self, PyObject *args) | |
| { | |
| const char *printable_filename; | |
| PyObject *temp; | |
| void *handle; | |
| DynLibObject *dlobj = NULL; | |
| int auto_close; | |
| handle = b_do_dlopen(args, &printable_filename, &temp, &auto_close); | |
| if (handle == NULL) | |
| goto error; | |
| dlobj = PyObject_New(DynLibObject, &dl_type); | |
| if (dlobj == NULL) { | |
| dlclose(handle); | |
| goto error; | |
| } | |
| dlobj->dl_handle = handle; | |
| dlobj->dl_name = strdup(printable_filename); | |
| dlobj->dl_auto_close = auto_close; | |
| error: | |
| Py_XDECREF(temp); | |
| return (PyObject *)dlobj; | |
| } | |
| /************************************************************/ | |
| static PyObject *get_unique_type(CTypeDescrObject *x, | |
| const void *unique_key[], long keylength) | |
| { | |
| /* Replace the CTypeDescrObject 'x' with a standardized one. | |
| This either just returns x, or x is decrefed and a new reference | |
| to the already-existing equivalent is returned. | |
| In this function, 'x' always contains a reference that must be | |
| either decrefed or returned. | |
| Keys: | |
| void ["void"] | |
| primitive [&static_struct] | |
| pointer [ctype] | |
| array [ctype, length] | |
| funcptr [ctresult, ellipsis+abi, num_args, ctargs...] | |
| */ | |
| PyObject *key, *y; | |
| void *pkey; | |
| key = PyBytes_FromStringAndSize(NULL, keylength * sizeof(void *)); | |
| if (key == NULL) | |
| goto error; | |
| pkey = PyBytes_AS_STRING(key); | |
| memcpy(pkey, unique_key, keylength * sizeof(void *)); | |
| y = PyDict_GetItem(unique_cache, key); | |
| if (y != NULL) { | |
| Py_DECREF(key); | |
| Py_INCREF(y); | |
| Py_DECREF(x); | |
| return y; | |
| } | |
| if (PyDict_SetItem(unique_cache, key, (PyObject *)x) < 0) { | |
| Py_DECREF(key); | |
| goto error; | |
| } | |
| /* Haaaack for our reference count hack: gcmodule.c must not see this | |
| dictionary. The problem is that any PyDict_SetItem() notices that | |
| 'x' is tracked and re-tracks the unique_cache dictionary. So here | |
| we re-untrack it again... */ | |
| PyObject_GC_UnTrack(unique_cache); | |
| assert(x->ct_unique_key == NULL); | |
| x->ct_unique_key = key; /* the key will be freed in ctypedescr_dealloc() */ | |
| /* the 'value' in unique_cache doesn't count as 1, but don't use | |
| Py_DECREF(x) here because it will confuse debug builds into thinking | |
| there was an extra DECREF in total. */ | |
| ((PyObject *)x)->ob_refcnt--; | |
| return (PyObject *)x; | |
| error: | |
| Py_DECREF(x); | |
| return NULL; | |
| } | |
| /* according to the C standard, these types should be equivalent to the | |
| _Complex types for the purposes of storage (not arguments in calls!) */ | |
| typedef float cffi_float_complex_t[2]; | |
| typedef double cffi_double_complex_t[2]; | |
| static PyObject *new_primitive_type(const char *name) | |
| { | |
| #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 ) \ | |
| EPTYPE2(fc, "float _Complex", cffi_float_complex_t, CT_PRIMITIVE_COMPLEX ) \ | |
| EPTYPE2(dc, "double _Complex", cffi_double_complex_t, CT_PRIMITIVE_COMPLEX ) \ | |
| ENUM_PRIMITIVE_TYPES_WCHAR \ | |
| EPTYPE2(c16, "char16_t", cffi_char16_t, CT_PRIMITIVE_CHAR ) \ | |
| EPTYPE2(c32, "char32_t", cffi_char32_t, CT_PRIMITIVE_CHAR ) \ | |
| 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) \ | |
| EPTYPE2(ssz, "ssize_t", Py_ssize_t, CT_PRIMITIVE_SIGNED) | |
| #ifdef HAVE_WCHAR_H | |
| # define ENUM_PRIMITIVE_TYPES_WCHAR \ | |
| EPTYPE(wc, wchar_t, CT_PRIMITIVE_CHAR | \ | |
| (((wchar_t)-1) > 0 ? 0 : CT_IS_SIGNED_WCHAR)) | |
| #else | |
| # define ENUM_PRIMITIVE_TYPES_WCHAR /* nothing */ | |
| #endif | |
| #define EPTYPE(code, typename, flags) EPTYPE2(code, #typename, typename, flags) | |
| #define EPTYPE2(code, export_name, typename, flags) \ | |
| struct aligncheck_##code { char x; typename y; }; | |
| ENUM_PRIMITIVE_TYPES | |
| #undef EPTYPE2 | |
| CTypeDescrObject *td; | |
| static const struct descr_s { const char *name; int size, align, flags; } | |
| types[] = { | |
| #define EPTYPE2(code, export_name, typename, flags) \ | |
| { export_name, \ | |
| sizeof(typename), \ | |
| offsetof(struct aligncheck_##code, y), \ | |
| flags \ | |
| }, | |
| ENUM_PRIMITIVE_TYPES | |
| #undef EPTYPE2 | |
| #undef EPTYPE | |
| #undef ENUM_PRIMITIVE_TYPES_WCHAR | |
| #undef ENUM_PRIMITIVE_TYPES | |
| { NULL } | |
| }; | |
| const struct descr_s *ptypes; | |
| const void *unique_key[1]; | |
| int name_size; | |
| ffi_type *ffitype; | |
| 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) { | |
| /* assume that if sizeof(double) == sizeof(long double), then | |
| the two types are equivalent for C. libffi bugs on Win64 | |
| if a function's return type is ffi_type_longdouble... */ | |
| if (sizeof(double) == sizeof(long double)) | |
| ffitype = &ffi_type_double; | |
| else | |
| ffitype = &ffi_type_longdouble; | |
| } | |
| else | |
| goto bad_ffi_type; | |
| } | |
| else if (ptypes->flags & CT_PRIMITIVE_COMPLEX) { | |
| /* As of March 2017, still no libffi support for complex. | |
| It fails silently if we try to use ffi_type_complex_float | |
| or ffi_type_complex_double. Better not use it at all. | |
| */ | |
| ffitype = NULL; | |
| } | |
| 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 <= (Py_ssize_t)sizeof(long)) | |
| td->ct_flags |= CT_PRIMITIVE_FITS_LONG; | |
| } | |
| else if (td->ct_flags & CT_PRIMITIVE_UNSIGNED) { | |
| if (td->ct_size < (Py_ssize_t)sizeof(long)) | |
| td->ct_flags |= CT_PRIMITIVE_FITS_LONG; | |
| } | |
| td->ct_name_position = strlen(td->ct_name); | |
| unique_key[0] = ptypes; | |
| return get_unique_type(td, unique_key, 1); | |
| 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_primitive_type(PyObject *self, PyObject *args) | |
| { | |
| char *name; | |
| if (!PyArg_ParseTuple(args, "s:new_primitive_type", &name)) | |
| return NULL; | |
| return new_primitive_type(name); | |
| } | |
| static PyObject *new_pointer_type(CTypeDescrObject *ctitem) | |
| { | |
| CTypeDescrObject *td; | |
| const char *extra; | |
| const void *unique_key[1]; | |
| 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_IS_VOIDCHAR_PTR; /* 'void *' or 'char *' only */ | |
| unique_key[0] = ctitem; | |
| return get_unique_type(td, unique_key, 1); | |
| } | |
| static PyObject *b_new_pointer_type(PyObject *self, PyObject *args) | |
| { | |
| CTypeDescrObject *ctitem; | |
| if (!PyArg_ParseTuple(args, "O!:new_pointer_type", | |
| &CTypeDescr_Type, &ctitem)) | |
| return NULL; | |
| return new_pointer_type(ctitem); | |
| } | |
| static PyObject *b_new_array_type(PyObject *self, PyObject *args) | |
| { | |
| PyObject *lengthobj; | |
| Py_ssize_t length; | |
| CTypeDescrObject *ctptr; | |
| if (!PyArg_ParseTuple(args, "O!O:new_array_type", | |
| &CTypeDescr_Type, &ctptr, &lengthobj)) | |
| return NULL; | |
| if (lengthobj == Py_None) { | |
| length = -1; | |
| } | |
| else { | |
| length = PyNumber_AsSsize_t(lengthobj, PyExc_OverflowError); | |
| if (length < 0) { | |
| if (!PyErr_Occurred()) | |
| PyErr_SetString(PyExc_ValueError, "negative array length"); | |
| return NULL; | |
| } | |
| } | |
| return new_array_type(ctptr, length); | |
| } | |
| static PyObject * | |
| new_array_type(CTypeDescrObject *ctptr, Py_ssize_t length) | |
| { | |
| CTypeDescrObject *td, *ctitem; | |
| char extra_text[32]; | |
| Py_ssize_t arraysize; | |
| int flags = CT_ARRAY; | |
| const void *unique_key[2]; | |
| 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 (length < 0) { | |
| sprintf(extra_text, "[]"); | |
| length = -1; | |
| arraysize = -1; | |
| } | |
| else { | |
| sprintf(extra_text, "[%llu]", (unsigned PY_LONG_LONG)length); | |
| arraysize = MUL_WRAPAROUND(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 = flags; | |
| unique_key[0] = ctptr; | |
| unique_key[1] = (void *)length; | |
| return get_unique_type(td, unique_key, 2); | |
| } | |
| static PyObject *new_void_type(void) | |
| { | |
| int name_size = strlen("void") + 1; | |
| const void *unique_key[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"); | |
| unique_key[0] = "void"; | |
| return get_unique_type(td, unique_key, 1); | |
| } | |
| static PyObject *b_new_void_type(PyObject *self, PyObject *args) | |
| { | |
| return new_void_type(); | |
| } | |
| static PyObject *new_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; | |
| td->ct_extra = NULL; | |
| 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 new_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 new_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 flags) | |
| { | |
| 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; | |
| cf->cf_flags = flags; | |
| 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 | |
| #define SF_STD_FIELD_POS 0x80 | |
| #ifdef MS_WIN32 | |
| # define SF_DEFAULT_PACKING 8 | |
| #else | |
| # define SF_DEFAULT_PACKING 0x40000000 /* a huge power of two */ | |
| #endif | |
| 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(__APPLE__) && defined(__arm64__) | |
| sflags |= SF_GCC_X86_BITFIELDS; | |
| # elif 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 int detect_custom_layout(CTypeDescrObject *ct, int sflags, | |
| Py_ssize_t cdef_value, | |
| Py_ssize_t compiler_value, | |
| const char *msg1, const char *txt, | |
| const char *msg2) | |
| { | |
| if (compiler_value != cdef_value) { | |
| if (sflags & SF_STD_FIELD_POS) { | |
| PyErr_Format(FFIError, | |
| "%s: %s%s%s (cdef says %zd, but C compiler says %zd)." | |
| " fix it or use \"...;\" as the last field in the " | |
| "cdef for %s to make it flexible", | |
| ct->ct_name, msg1, txt, msg2, | |
| cdef_value, compiler_value, | |
| ct->ct_name); | |
| return -1; | |
| } | |
| ct->ct_flags |= CT_CUSTOM_FIELD_POS; | |
| } | |
| return 0; | |
| } | |
| #define ROUNDUP_BYTES(bytes, bits) ((bytes) + ((bits) > 0)) | |
| 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 byteoffset, i, nb_fields, byteoffsetmax, alignedsize; | |
| int bitoffset; | |
| Py_ssize_t byteoffsetorg; | |
| Py_ssize_t totalsize = -1; | |
| int totalalignment = -1; | |
| CFieldObject **previous; | |
| int prev_bitfield_size, prev_bitfield_free; | |
| int sflags = 0, fflags; | |
| int pack = 0; | |
| if (!PyArg_ParseTuple(args, "O!O!|Oniii:complete_struct_or_union", | |
| &CTypeDescr_Type, &ct, | |
| &PyList_Type, &fields, | |
| &ignored, &totalsize, &totalalignment, &sflags, | |
| &pack)) | |
| return NULL; | |
| sflags = complete_sflags(sflags); | |
| if (sflags & SF_PACKED) | |
| pack = 1; | |
| else if (pack <= 0) | |
| pack = SF_DEFAULT_PACKING; | |
| else | |
| sflags |= SF_PACKED; | |
| 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; | |
| } | |
| ct->ct_flags &= ~(CT_CUSTOM_FIELD_POS | CT_WITH_PACKED_CHANGE); | |
| alignment = 1; | |
| byteoffset = 0; /* the real value is 'byteoffset+bitoffset*8', which */ | |
| bitoffset = 0; /* counts the offset in bits */ | |
| byteoffsetmax = 0; /* the maximum value of byteoffset-rounded-up-to-byte */ | |
| 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; i<nb_fields; i++) { | |
| PyObject *fname; | |
| CTypeDescrObject *ftype; | |
| int fbitsize = -1, falign, falignorg, do_align; | |
| Py_ssize_t foffset = -1; | |
| if (!PyArg_ParseTuple(PyList_GET_ITEM(fields, i), "O!O!|in:list item", | |
| &PyText_Type, &fname, | |
| &CTypeDescr_Type, &ftype, | |
| &fbitsize, &foffset)) | |
| goto error; | |
| if (ftype->ct_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; | |
| } | |
| } | |
| else if (ftype->ct_flags & (CT_STRUCT|CT_UNION)) { | |
| if (force_lazy_struct(ftype) < 0) /* for CT_WITH_VAR_ARRAY */ | |
| return NULL; | |
| /* GCC (or maybe C99) accepts var-sized struct fields that are not | |
| the last field of a larger struct. That's why there is no | |
| check here for "last field": we propagate the flag | |
| CT_WITH_VAR_ARRAY to any struct that contains either an open- | |
| ended array or another struct that recursively contains an | |
| open-ended array. */ | |
| if (ftype->ct_flags & CT_WITH_VAR_ARRAY) | |
| ct->ct_flags |= CT_WITH_VAR_ARRAY; | |
| } | |
| if (is_union) | |
| byteoffset = bitoffset = 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 */ | |
| falignorg = get_alignment(ftype); | |
| if (falignorg < 0) | |
| goto error; | |
| falign = (pack < falignorg) ? pack : falignorg; | |
| 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; | |
| fflags = (is_union && i > 0) ? BF_IGNORE_IN_CTOR : 0; | |
| 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 */ | |
| /* first, pad to the next byte, | |
| * then pad to 'falign' or 'falignorg' bytes */ | |
| byteoffset = ROUNDUP_BYTES(byteoffset, bitoffset); | |
| bitoffset = 0; | |
| byteoffsetorg = (byteoffset + falignorg-1) & ~(falignorg-1); | |
| byteoffset = (byteoffset + falign-1) & ~(falign-1); | |
| if (byteoffsetorg != byteoffset) { | |
| ct->ct_flags |= CT_WITH_PACKED_CHANGE; | |
| } | |
| if (foffset >= 0) { | |
| /* a forced field position: ignore the offset just computed, | |
| except to know if we must set CT_CUSTOM_FIELD_POS */ | |
| if (detect_custom_layout(ct, sflags, byteoffset, foffset, | |
| "wrong offset for field '", | |
| PyText_AS_UTF8(fname), "'") < 0) | |
| goto error; | |
| byteoffset = foffset; | |
| } | |
| 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, | |
| byteoffset + cfsrc->cf_offset, | |
| cfsrc->cf_bitshift, | |
| cfsrc->cf_bitsize, | |
| cfsrc->cf_flags | fflags); | |
| 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, | |
| byteoffset, bs_flag, -1, fflags); | |
| if (*previous == NULL) | |
| goto error; | |
| previous = &(*previous)->cf_next; | |
| } | |
| if (ftype->ct_size >= 0) | |
| byteoffset += ftype->ct_size; | |
| 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 = byteoffset; | |
| 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 byteoffset to a value aligned for "ftype" */ | |
| if (ROUNDUP_BYTES(byteoffset, bitoffset) > field_offset_bytes) { | |
| field_offset_bytes += falign; | |
| assert(byteoffset < field_offset_bytes); | |
| } | |
| byteoffset = field_offset_bytes; | |
| bitoffset = 0; | |
| } | |
| 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 = (byteoffset-field_offset_bytes) * 8 | |
| + bitoffset; | |
| 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(byteoffset < field_offset_bytes); | |
| byteoffset = field_offset_bytes; | |
| bitoffset = 0; | |
| bitshift = 0; | |
| } | |
| else { | |
| bitshift = bits_already_occupied; | |
| assert(bitshift >= 0); | |
| } | |
| bitoffset += fbitsize; | |
| byteoffset += (bitoffset >> 3); | |
| bitoffset &= 7; | |
| } | |
| 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 */ | |
| byteoffset = ROUNDUP_BYTES(byteoffset, bitoffset); | |
| bitoffset = 0; | |
| /* align */ | |
| byteoffset = (byteoffset + falign-1) & ~(falign-1); | |
| byteoffset += ftype->ct_size; | |
| bitshift = 0; | |
| prev_bitfield_size = ftype->ct_size; | |
| prev_bitfield_free = 8 * prev_bitfield_size; | |
| } | |
| prev_bitfield_free -= fbitsize; | |
| field_offset_bytes = byteoffset - ftype->ct_size; | |
| } | |
| if (sflags & SF_GCC_BIG_ENDIAN) | |
| bitshift = 8 * ftype->ct_size - fbitsize - bitshift; | |
| if (PyText_GetSize(fname) > 0) { | |
| *previous = _add_field(interned_fields, fname, ftype, | |
| field_offset_bytes, bitshift, fbitsize, | |
| fflags); | |
| if (*previous == NULL) | |
| goto error; | |
| previous = &(*previous)->cf_next; | |
| } | |
| } | |
| } | |
| assert(bitoffset == (bitoffset & 7)); | |
| if (ROUNDUP_BYTES(byteoffset, bitoffset) > byteoffsetmax) | |
| byteoffsetmax = ROUNDUP_BYTES(byteoffset, bitoffset); | |
| } | |
| *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. */ | |
| alignedsize = (byteoffsetmax + alignment - 1) & ~(alignment-1); | |
| if (alignedsize == 0) | |
| alignedsize = 1; | |
| if (totalsize < 0) { | |
| totalsize = alignedsize; | |
| } | |
| else { | |
| if (detect_custom_layout(ct, sflags, alignedsize, | |
| totalsize, "wrong total size", "", "") < 0) | |
| goto error; | |
| if (totalsize < byteoffsetmax) { | |
| PyErr_Format(PyExc_TypeError, | |
| "%s cannot be of size %zd: there are fields at least " | |
| "up to %zd", ct->ct_name, totalsize, byteoffsetmax); | |
| goto error; | |
| } | |
| } | |
| if (totalalignment < 0) { | |
| totalalignment = alignment; | |
| } | |
| else { | |
| if (detect_custom_layout(ct, sflags, alignment, totalalignment, | |
| "wrong total alignment", "", "") < 0) | |
| goto error; | |
| } | |
| ct->ct_size = totalsize; | |
| ct->ct_length = totalalignment; | |
| ct->ct_stuff = interned_fields; | |
| ct->ct_flags &= ~CT_IS_OPAQUE; | |
| Py_INCREF(Py_None); | |
| return Py_None; | |
| error: | |
| ct->ct_extra = NULL; | |
| 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; | |
| } | |
| } | |
| #define SUPPORTED_IN_API_MODE \ | |
| " are only supported as %s if the function is " \ | |
| "'API mode' and non-variadic (i.e. declared inside ffibuilder" \ | |
| ".cdef()+ffibuilder.set_source() and not taking a final '...' " \ | |
| "argument)" | |
| static ffi_type *fb_unsupported(CTypeDescrObject *ct, const char *place, | |
| const char *detail) | |
| { | |
| PyErr_Format(PyExc_NotImplementedError, | |
| "ctype '%s' not supported as %s. %s. " | |
| "Such structs" SUPPORTED_IN_API_MODE, | |
| ct->ct_name, place, detail, place); | |
| return NULL; | |
| } | |
| static ffi_type *fb_fill_type(struct funcbuilder_s *fb, CTypeDescrObject *ct, | |
| int is_result_type) | |
| { | |
| const char *place = is_result_type ? "return value" : "argument"; | |
| if (ct->ct_flags & (CT_PRIMITIVE_ANY & ~CT_PRIMITIVE_COMPLEX)) { | |
| 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). Note: it seems we only get in this case with | |
| ffi.verify(). | |
| */ | |
| if (force_lazy_struct(ct) < 0) | |
| return NULL; | |
| if (ct->ct_flags & CT_CUSTOM_FIELD_POS) { | |
| /* these NotImplementedErrors may be caught and ignored until | |
| a real call is made to a function of this type */ | |
| return fb_unsupported(ct, place, | |
| "It is a struct declared with \"...;\", but the C " | |
| "calling convention may depend on the missing fields; " | |
| "or, it contains anonymous struct/unions"); | |
| } | |
| /* Another reason: __attribute__((packed)) is not supported by libffi. | |
| */ | |
| if (ct->ct_flags & CT_WITH_PACKED_CHANGE) { | |
| return fb_unsupported(ct, place, | |
| "It is a 'packed' structure, with a different layout than " | |
| "expected by libffi"); | |
| } | |
| 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; i<n; i++) { | |
| Py_ssize_t flat; | |
| CTypeDescrObject *ct1; | |
| assert(cf != NULL); | |
| if (cf->cf_bitshift >= 0) { | |
| return fb_unsupported(ct, place, | |
| "It is a struct with bit fields, which libffi does not " | |
| "support"); | |
| } | |
| flat = 1; | |
| ct1 = cf->cf_type; | |
| while (ct1->ct_flags & CT_ARRAY) { | |
| flat *= ct1->ct_length; | |
| ct1 = ct1->ct_itemdescr; | |
| } | |
| if (flat <= 0) { | |
| return fb_unsupported(ct, place, | |
| "It is a struct with a zero-length array, which libffi " | |
| "does not support"); | |
| } | |
| 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; i<n; i++) { | |
| Py_ssize_t j, flat = 1; | |
| CTypeDescrObject *ct = cf->cf_type; | |
| while (ct->ct_flags & CT_ARRAY) { | |
| flat *= ct->ct_length; | |
| ct = ct->ct_itemdescr; | |
| } | |
| ffifield = fb_fill_type(fb, ct, 0); | |
| if (PyErr_Occurred()) | |
| return NULL; | |
| if (elements != NULL) { | |
| for (j=0; j<flat; j++) | |
| elements[nflat++] = ffifield; | |
| } | |
| cf = cf->cf_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 if (ct->ct_flags & CT_UNION) { | |
| PyErr_Format(PyExc_NotImplementedError, | |
| "ctype '%s' not supported as %s by libffi. " | |
| "Unions" SUPPORTED_IN_API_MODE, | |
| ct->ct_name, place, place); | |
| return NULL; | |
| } | |
| else { | |
| char *extra = ""; | |
| if (ct->ct_flags & CT_PRIMITIVE_COMPLEX) | |
| extra = " (the support for complex types inside libffi " | |
| "is mostly missing at this point, so CFFI only " | |
| "supports complex types as arguments or return " | |
| "value in API-mode functions)"; | |
| PyErr_Format(PyExc_NotImplementedError, | |
| "ctype '%s' (size %zd) not supported as %s%s", | |
| ct->ct_name, ct->ct_size, place, extra); | |
| 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; i<nargs; i++) { | |
| CTypeDescrObject *farg; | |
| ffi_type *atype; | |
| farg = (CTypeDescrObject *)PyTuple_GET_ITEM(fargs, i); | |
| /* convert arrays to pointers */ | |
| if (farg->ct_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 */ | |
| /* we also align it to the next multiple of 8, in an attempt to | |
| work around bugs(?) of libffi like #241 */ | |
| cif_descr->exchange_size = ALIGN_ARG(exchange_offset); | |
| } | |
| return 0; | |
| } | |
| #undef ALIGN_ARG | |
| static void fb_cat_name(struct funcbuilder_s *fb, const 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, const char *repl, | |
| CTypeDescrObject **pfargs, Py_ssize_t nargs, | |
| CTypeDescrObject *fresult, int ellipsis) | |
| { | |
| Py_ssize_t i; | |
| 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); | |
| if (repl[0] != '(' && | |
| fresult->ct_name[fresult->ct_name_position - 1] != '*') | |
| fb_cat_name(fb, " ", 1); /* add a space */ | |
| fb_cat_name(fb, repl, strlen(repl)); | |
| if (fb->fct) { | |
| i = strlen(repl) - 1; /* between '(*' and ')' */ | |
| assert(repl[i] == ')'); | |
| fb->fct->ct_name_position = fresult->ct_name_position + i; | |
| } | |
| fb_cat_name(fb, "(", 1); | |
| /* loop over the arguments */ | |
| for (i=0; i<nargs; i++) { | |
| CTypeDescrObject *farg; | |
| farg = pfargs[i]; | |
| if (!CTypeDescr_Check(farg)) { | |
| PyErr_SetString(PyExc_TypeError, "expected a tuple of ctypes"); | |
| return -1; | |
| } | |
| /* name: concatenate the name of the i'th argument's type */ | |
| if (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, int fabi) | |
| { | |
| CTypeDescrObject *fct, **pfargs; | |
| Py_ssize_t nargs; | |
| char *repl = "(*)"; | |
| fb->nb_bytes = 0; | |
| fb->bufferp = NULL; | |
| fb->fct = NULL; | |
| pfargs = (CTypeDescrObject **)&PyTuple_GET_ITEM(fargs, 0); | |
| nargs = PyTuple_GET_SIZE(fargs); | |
| #if defined(MS_WIN32) && !defined(_WIN64) | |
| if (fabi == FFI_STDCALL) | |
| repl = "(__stdcall *)"; | |
| #endif | |
| /* compute the total size needed for the name */ | |
| if (fb_build_name(fb, repl, pfargs, nargs, 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, repl, pfargs, nargs, 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, | |
| Py_ssize_t variadic_nargs_declared, | |
| ffi_abi fabi) | |
| { | |
| char *buffer; | |
| cif_description_t *cif_descr; | |
| struct funcbuilder_s funcbuffer; | |
| ffi_status status = (ffi_status)-1; | |
| 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; | |
| /* use `ffi_prep_cif_var` if necessary and available */ | |
| #if CFFI_CHECK_FFI_PREP_CIF_VAR_MAYBE | |
| if (variadic_nargs_declared >= 0) { | |
| if (CFFI_CHECK_FFI_PREP_CIF_VAR) { | |
| status = ffi_prep_cif_var(&cif_descr->cif, fabi, | |
| variadic_nargs_declared, funcbuffer.nargs, | |
| funcbuffer.rtype, funcbuffer.atypes); | |
| } | |
| } | |
| #endif | |
| if (status == (ffi_status)-1) { | |
| status = ffi_prep_cif(&cif_descr->cif, fabi, funcbuffer.nargs, | |
| funcbuffer.rtype, funcbuffer.atypes); | |
| } | |
| if (status != 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 *new_function_type(PyObject *fargs, /* tuple */ | |
| CTypeDescrObject *fresult, | |
| int ellipsis, int fabi) | |
| { | |
| PyObject *fabiobj; | |
| CTypeDescrObject *fct; | |
| struct funcbuilder_s funcbuilder; | |
| Py_ssize_t i; | |
| const void **unique_key; | |
| 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, fabi); | |
| 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, -1, fabi); | |
| if (cif_descr == NULL) { | |
| if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { | |
| PyErr_Clear(); /* will get the exception if we see an | |
| actual call */ | |
| } | |
| else | |
| 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; i<funcbuilder.nargs; i++) { | |
| PyObject *o = PyTuple_GET_ITEM(fargs, i); | |
| /* convert arrays into pointers */ | |
| if (((CTypeDescrObject *)o)->ct_flags & CT_ARRAY) | |
| o = ((CTypeDescrObject *)o)->ct_stuff; | |
| Py_INCREF(o); | |
| PyTuple_SET_ITEM(fct->ct_stuff, 2 + i, o); | |
| } | |
| /* [ctresult, ellipsis+abi, num_args, ctargs...] */ | |
| unique_key = alloca((3 + funcbuilder.nargs) * sizeof(void *)); | |
| unique_key[0] = fresult; | |
| unique_key[1] = (const void *)(Py_ssize_t)((fabi << 1) | !!ellipsis); | |
| unique_key[2] = (const void *)(Py_ssize_t)(funcbuilder.nargs); | |
| for (i=0; i<funcbuilder.nargs; i++) | |
| unique_key[3 + i] = PyTuple_GET_ITEM(fct->ct_stuff, 2 + i); | |
| return get_unique_type(fct, unique_key, 3 + funcbuilder.nargs); | |
| error: | |
| Py_DECREF(fct); | |
| return NULL; | |
| } | |
| static PyObject *b_new_function_type(PyObject *self, PyObject *args) | |
| { | |
| PyObject *fargs; | |
| CTypeDescrObject *fresult; | |
| int ellipsis = 0, fabi = FFI_DEFAULT_ABI; | |
| if (!PyArg_ParseTuple(args, "O!O!|ii:new_function_type", | |
| &PyTuple_Type, &fargs, | |
| &CTypeDescr_Type, &fresult, | |
| &ellipsis, | |
| &fabi)) | |
| return NULL; | |
| return new_function_type(fargs, fresult, ellipsis, fabi); | |
| } | |
| static int convert_from_object_fficallback(char *result, | |
| CTypeDescrObject *ctype, | |
| PyObject *pyobj, | |
| int encode_result_for_libffi) | |
| { | |
| /* 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 (!encode_result_for_libffi) | |
| goto skip; | |
| 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 | | |
| CT_POINTER | CT_FUNCTIONPTR)) { | |
| /* zero extension: fill the '*result' with zeros, and (on big- | |
| endian machines) correct the 'result' pointer to write to. | |
| We also do that for pointers, even though we're normally not | |
| in this branch because ctype->ct_size == sizeof(ffi_arg) for | |
| pointers---except on some architectures like x32 (issue #372). | |
| */ | |
| memset(result, 0, sizeof(ffi_arg)); | |
| #ifdef WORDS_BIGENDIAN | |
| result += (sizeof(ffi_arg) - ctype->ct_size); | |
| #endif | |
| } | |
| } | |
| skip: | |
| return convert_from_object(result, ctype, pyobj); | |
| } | |
| static void _my_PyErr_WriteUnraisable(PyObject *t, PyObject *v, PyObject *tb, | |
| char *objdescr, PyObject *obj, | |
| char *extra_error_line) | |
| { | |
| /* like PyErr_WriteUnraisable(), but write a full traceback */ | |
| #ifdef USE_WRITEUNRAISABLEMSG | |
| /* PyErr_WriteUnraisable actually writes the full traceback anyway | |
| from Python 3.4, but we can't really get the formatting of the | |
| custom text to be what we want. We can do better from Python | |
| 3.8 by calling the new _PyErr_WriteUnraisableMsg(). | |
| Luckily it's also Python 3.8 that adds new functionality that | |
| people might want: the new sys.unraisablehook(). | |
| */ | |
| PyObject *s; | |
| int first_char; | |
| assert(objdescr != NULL && objdescr[0] != 0); /* non-empty */ | |
| first_char = objdescr[0]; | |
| if (first_char >= 'A' && first_char <= 'Z') | |
| first_char += 'a' - 'A'; /* lower() the very first character */ | |
| if (extra_error_line == NULL) | |
| extra_error_line = ""; | |
| if (obj != NULL) | |
| s = PyUnicode_FromFormat("%c%s%R%s", | |
| first_char, objdescr + 1, obj, extra_error_line); | |
| else | |
| s = PyUnicode_FromFormat("%c%s%s", | |
| first_char, objdescr + 1, extra_error_line); | |
| PyErr_Restore(t, v, tb); | |
| if (s != NULL) { | |
| _PyErr_WriteUnraisableMsg(PyText_AS_UTF8(s), NULL); | |
| Py_DECREF(s); | |
| } | |
| else | |
| PyErr_WriteUnraisable(obj); /* best effort */ | |
| PyErr_Clear(); | |
| #else | |
| /* version for Python 2.7 and < 3.8 */ | |
| PyObject *f; | |
| #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) { | |
| if (obj != NULL) { | |
| PyFile_WriteString(objdescr, 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); | |
| #endif | |
| } | |
| static void general_invoke_callback(int decode_args_from_libffi, | |
| void *result, char *args, void *userdata) | |
| { | |
| 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; | |
| PyObject *onerror_cb; | |
| 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; i<n; i++) { | |
| char *a_src; | |
| PyObject *a; | |
| CTypeDescrObject *a_ct = SIGNATURE(2 + i); | |
| if (decode_args_from_libffi) { | |
| a_src = ((void **)args)[i]; | |
| } | |
| else { | |
| a_src = args + i * 8; | |
| if (a_ct->ct_flags & (CT_IS_LONGDOUBLE | CT_STRUCT | CT_UNION)) | |
| a_src = *(char **)a_src; | |
| } | |
| a = convert_to_object(a_src, a_ct); | |
| if (a == NULL) | |
| goto error; | |
| PyTuple_SET_ITEM(py_args, i, a); | |
| } | |
| py_res = PyObject_Call(py_ob, py_args, NULL); | |
| if (py_res == NULL) | |
| goto error; | |
| if (convert_from_object_fficallback(result, SIGNATURE(1), py_res, | |
| decode_args_from_libffi) < 0) { | |
| #ifdef USE_WRITEUNRAISABLEMSG | |
| extra_error_line = ", trying to convert the result back to C"; | |
| #else | |
| extra_error_line = "Trying to convert the result back to C:\n"; | |
| #endif | |
| goto error; | |
| } | |
| done: | |
| Py_XDECREF(py_args); | |
| Py_XDECREF(py_res); | |
| Py_DECREF(cb_args); | |
| return; | |
| error: | |
| if (SIGNATURE(1)->ct_size > 0) { | |
| py_rawerr = PyTuple_GET_ITEM(cb_args, 2); | |
| memcpy(result, PyBytes_AS_STRING(py_rawerr), | |
| PyBytes_GET_SIZE(py_rawerr)); | |
| } | |
| onerror_cb = PyTuple_GET_ITEM(cb_args, 3); | |
| if (onerror_cb == Py_None) { | |
| PyObject *ecap, *t, *v, *tb; | |
| PyErr_Fetch(&t, &v, &tb); | |
| ecap = _cffi_start_error_capture(); | |
| _my_PyErr_WriteUnraisable(t, v, tb, "From cffi callback ", py_ob, | |
| extra_error_line); | |
| _cffi_stop_error_capture(ecap); | |
| } | |
| else { | |
| PyObject *exc1, *val1, *tb1, *res1, *exc2, *val2, *tb2; | |
| PyErr_Fetch(&exc1, &val1, &tb1); | |
| PyErr_NormalizeException(&exc1, &val1, &tb1); | |
| res1 = PyObject_CallFunctionObjArgs(onerror_cb, | |
| exc1 ? exc1 : Py_None, | |
| val1 ? val1 : Py_None, | |
| tb1 ? tb1 : Py_None, | |
| NULL); | |
| if (res1 != NULL) { | |
| if (res1 != Py_None) | |
| convert_from_object_fficallback(result, SIGNATURE(1), res1, | |
| decode_args_from_libffi); | |
| Py_DECREF(res1); | |
| } | |
| if (!PyErr_Occurred()) { | |
| Py_XDECREF(exc1); | |
| Py_XDECREF(val1); | |
| Py_XDECREF(tb1); | |
| } | |
| else { | |
| /* double exception! print a double-traceback... */ | |
| PyObject *ecap; | |
| PyErr_Fetch(&exc2, &val2, &tb2); | |
| ecap = _cffi_start_error_capture(); | |
| _my_PyErr_WriteUnraisable(exc1, val1, tb1, | |
| "From cffi callback ", py_ob, | |
| extra_error_line); | |
| #ifdef USE_WRITEUNRAISABLEMSG | |
| _my_PyErr_WriteUnraisable(exc2, val2, tb2, | |
| "during handling of the above exception by 'onerror'", | |
| NULL, NULL); | |
| #else | |
| extra_error_line = ("\nDuring the call to 'onerror', " | |
| "another exception occurred:\n\n"); | |
| _my_PyErr_WriteUnraisable(exc2, val2, tb2, | |
| NULL, NULL, extra_error_line); | |
| #endif | |
| _cffi_stop_error_capture(ecap); | |
| } | |
| } | |
| goto done; | |
| #undef SIGNATURE | |
| } | |
| static void invoke_callback(ffi_cif *cif, void *result, void **args, | |
| void *userdata) | |
| { | |
| save_errno(); | |
| { | |
| PyGILState_STATE state = gil_ensure(); | |
| general_invoke_callback(1, result, (char *)args, userdata); | |
| gil_release(state); | |
| } | |
| restore_errno(); | |
| } | |
| static PyObject *prepare_callback_info_tuple(CTypeDescrObject *ct, | |
| PyObject *ob, | |
| PyObject *error_ob, | |
| PyObject *onerror_ob, | |
| int decode_args_from_libffi) | |
| { | |
| CTypeDescrObject *ctresult; | |
| PyObject *py_rawerr, *infotuple; | |
| Py_ssize_t size; | |
| 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; | |
| } | |
| if (onerror_ob != Py_None && !PyCallable_Check(onerror_ob)) { | |
| PyErr_Format(PyExc_TypeError, | |
| "expected a callable object for 'onerror', not %.200s", | |
| Py_TYPE(onerror_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, | |
| decode_args_from_libffi) < 0) { | |
| Py_DECREF(py_rawerr); | |
| return NULL; | |
| } | |
| } | |
| infotuple = Py_BuildValue("OOOO", ct, ob, py_rawerr, onerror_ob); | |
| Py_DECREF(py_rawerr); | |
| #if defined(WITH_THREAD) && PY_VERSION_HEX < 0x03070000 | |
| /* We must setup the GIL here, in case the callback is invoked in | |
| some other non-Pythonic thread. This is the same as ctypes. | |
| But PyEval_InitThreads() is always a no-op from CPython 3.7 | |
| (the call from ctypes was removed some time later I think). */ | |
| PyEval_InitThreads(); | |
| #endif | |
| return infotuple; | |
| } | |
| /* messily try to silence a gcc/clang deprecation warning for | |
| ffi_prep_closure. Don't miss the "pragma pop" after the function. | |
| This is done around the whole function because very old GCCs don't | |
| support it inside a function. */ | |
| #if defined(__clang__) | |
| # pragma clang diagnostic push | |
| # pragma clang diagnostic ignored "-Wdeprecated-declarations" | |
| #elif defined(__GNUC__) | |
| # pragma GCC diagnostic push | |
| # pragma GCC diagnostic ignored "-Wdeprecated-declarations" | |
| #endif | |
| static PyObject *b_callback(PyObject *self, PyObject *args) | |
| { | |
| CTypeDescrObject *ct; | |
| CDataObject_closure *cd; | |
| PyObject *ob, *error_ob = Py_None, *onerror_ob = Py_None; | |
| PyObject *infotuple; | |
| cif_description_t *cif_descr; | |
| ffi_closure *closure; | |
| ffi_status status; | |
| void *closure_exec; | |
| if (!PyArg_ParseTuple(args, "O!O|OO:callback", &CTypeDescr_Type, &ct, &ob, | |
| &error_ob, &onerror_ob)) | |
| return NULL; | |
| infotuple = prepare_callback_info_tuple(ct, ob, error_ob, onerror_ob, 1); | |
| if (infotuple == NULL) | |
| return NULL; | |
| #if CFFI_CHECK_FFI_CLOSURE_ALLOC_MAYBE | |
| if (CFFI_CHECK_FFI_CLOSURE_ALLOC) { | |
| closure = ffi_closure_alloc(sizeof(ffi_closure), &closure_exec); | |
| } else | |
| #endif | |
| { | |
| closure = cffi_closure_alloc(); | |
| closure_exec = closure; | |
| } | |
| if (closure == NULL) { | |
| Py_DECREF(infotuple); | |
| PyErr_SetString(PyExc_MemoryError, | |
| "Cannot allocate write+execute memory for ffi.callback(). " | |
| "You might be running on a system that prevents this. " | |
| "For more information, see " | |
| "https://cffi.readthedocs.io/en/latest/using.html#callbacks"); | |
| return NULL; | |
| } | |
| cd = PyObject_GC_New(CDataObject_closure, &CDataOwningGC_Type); | |
| if (cd == NULL) | |
| goto error; | |
| Py_INCREF(ct); | |
| cd->head.c_type = ct; | |
| cd->head.c_data = (char *)closure_exec; | |
| cd->head.c_weakreflist = NULL; | |
| closure->user_data = NULL; | |
| cd->closure = closure; | |
| cif_descr = (cif_description_t *)ct->ct_extra; | |
| if (cif_descr == NULL) { | |
| PyErr_Format(PyExc_NotImplementedError, | |
| "%s: callback with unsupported argument or " | |
| "return type or with '...'", ct->ct_name); | |
| goto error; | |
| } | |
| #if CFFI_CHECK_FFI_PREP_CLOSURE_LOC_MAYBE | |
| if (CFFI_CHECK_FFI_PREP_CLOSURE_LOC) { | |
| status = ffi_prep_closure_loc(closure, &cif_descr->cif, | |
| invoke_callback, infotuple, closure_exec); | |
| } | |
| else | |
| #endif | |
| { | |
| #if defined(__APPLE__) && defined(FFI_AVAILABLE_APPLE) && !FFI_LEGACY_CLOSURE_API | |
| PyErr_Format(PyExc_SystemError, "ffi_prep_closure_loc() is missing"); | |
| goto error; | |
| #else | |
| status = ffi_prep_closure(closure, &cif_descr->cif, | |
| invoke_callback, infotuple); | |
| #endif | |
| } | |
| if (status != FFI_OK) { | |
| PyErr_SetString(PyExc_SystemError, | |
| "libffi failed to build this callback"); | |
| goto error; | |
| } | |
| if (closure->user_data != infotuple) { | |
| /* Issue #266. Should not occur, but could, if we are using | |
| at runtime a version of libffi compiled with a different | |
| 'ffi_closure' structure than the one we expect from ffi.h | |
| (e.g. difference in details of the platform): a difference | |
| in FFI_TRAMPOLINE_SIZE means that the 'user_data' field | |
| ends up somewhere else, and so the test above fails. | |
| */ | |
| PyErr_SetString(PyExc_SystemError, | |
| "ffi_prep_closure(): bad user_data (it seems that the " | |
| "version of the libffi library seen at runtime is " | |
| "different from the 'ffi.h' file seen at compile-time)"); | |
| goto error; | |
| } | |
| PyObject_GC_Track(cd); | |
| return (PyObject *)cd; | |
| error: | |
| closure->user_data = NULL; | |
| if (cd == NULL) { | |
| #if CFFI_CHECK_FFI_CLOSURE_ALLOC_MAYBE | |
| if (CFFI_CHECK_FFI_CLOSURE_ALLOC) { | |
| ffi_closure_free(closure); | |
| } | |
| else | |
| #endif | |
| cffi_closure_free(closure); | |
| } | |
| else | |
| Py_DECREF(cd); | |
| Py_XDECREF(infotuple); | |
| return NULL; | |
| } | |
| #if defined(__clang__) | |
| # pragma clang diagnostic pop | |
| #elif defined(__GNUC__) | |
| # pragma GCC diagnostic pop | |
| #endif | |
| 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)) { | |
| const 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 Py_ssize_t direct_sizeof_cdata(CDataObject *cd) | |
| { | |
| Py_ssize_t size; | |
| if (cd->c_type->ct_flags & CT_ARRAY) | |
| size = get_array_length(cd) * cd->c_type->ct_itemdescr->ct_size; | |
| else { | |
| size = -1; | |
| if (cd->c_type->ct_flags & (CT_STRUCT | CT_UNION)) | |
| size = _cdata_var_byte_size(cd); | |
| if (size < 0) | |
| size = cd->c_type->ct_size; | |
| } | |
| return size; | |
| } | |
| static PyObject *b_sizeof(PyObject *self, PyObject *arg) | |
| { | |
| Py_ssize_t size; | |
| if (CData_Check(arg)) { | |
| size = direct_sizeof_cdata((CDataObject *)arg); | |
| } | |
| 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 CTypeDescrObject *direct_typeoffsetof(CTypeDescrObject *ct, | |
| PyObject *fieldname, | |
| int following, Py_ssize_t *offset) | |
| { | |
| /* Does not return a new reference! */ | |
| CTypeDescrObject *res; | |
| CFieldObject *cf; | |
| if (PyTextAny_Check(fieldname)) { | |
| if (!following && (ct->ct_flags & CT_POINTER)) | |
| ct = ct->ct_itemdescr; | |
| if (!(ct->ct_flags & (CT_STRUCT|CT_UNION))) { | |
| PyErr_SetString(PyExc_TypeError, | |
| "with a field name argument, expected a " | |
| "struct or union ctype"); | |
| return NULL; | |
| } | |
| if (force_lazy_struct(ct) <= 0) { | |
| if (!PyErr_Occurred()) | |
| PyErr_SetString(PyExc_TypeError, "struct/union is opaque"); | |
| 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 = cf->cf_type; | |
| *offset = cf->cf_offset; | |
| } | |
| else { | |
| Py_ssize_t index = PyInt_AsSsize_t(fieldname); | |
| if (index < 0 && PyErr_Occurred()) { | |
| PyErr_SetString(PyExc_TypeError, | |
| "field name or array index expected"); | |
| return NULL; | |
| } | |
| if (!(ct->ct_flags & (CT_ARRAY|CT_POINTER)) || | |
| ct->ct_itemdescr->ct_size < 0) { | |
| PyErr_SetString(PyExc_TypeError, "with an integer argument, " | |
| "expected an array ctype or a " | |
| "pointer to non-opaque"); | |
| return NULL; | |
| } | |
| res = ct->ct_itemdescr; | |
| *offset = MUL_WRAPAROUND(index, ct->ct_itemdescr->ct_size); | |
| if ((*offset / ct->ct_itemdescr->ct_size) != index) { | |
| PyErr_SetString(PyExc_OverflowError, | |
| "array offset would overflow a Py_ssize_t"); | |
| return NULL; | |
| } | |
| } | |
| return res; | |
| } | |
| static PyObject *b_typeoffsetof(PyObject *self, PyObject *args) | |
| { | |
| PyObject *res, *fieldname; | |
| CTypeDescrObject *ct; | |
| Py_ssize_t offset; | |
| int following = 0; | |
| if (!PyArg_ParseTuple(args, "O!O|i:typeoffsetof", | |
| &CTypeDescr_Type, &ct, &fieldname, &following)) | |
| return NULL; | |
| res = (PyObject *)direct_typeoffsetof(ct, fieldname, following, &offset); | |
| if (res == NULL) | |
| return NULL; | |
| return Py_BuildValue("(On)", res, offset); | |
| } | |
| static PyObject *b_rawaddressof(PyObject *self, PyObject *args) | |
| { | |
| CTypeDescrObject *ct; | |
| CDataObject *cd; | |
| Py_ssize_t offset; | |
| int accepted_flags; | |
| if (!PyArg_ParseTuple(args, "O!O!n:rawaddressof", | |
| &CTypeDescr_Type, &ct, | |
| &CData_Type, &cd, | |
| &offset)) | |
| return NULL; | |
| accepted_flags = CT_STRUCT | CT_UNION | CT_ARRAY | CT_POINTER; | |
| if ((cd->c_type->ct_flags & accepted_flags) == 0) { | |
| PyErr_SetString(PyExc_TypeError, | |
| "expected a cdata struct/union/array/pointer 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, PyObject *kwds) | |
| { | |
| CDataObject *cd; | |
| Py_ssize_t maxlen = -1; | |
| static char *keywords[] = {"cdata", "maxlen", NULL}; | |
| if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|n:string", keywords, | |
| &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) && | |
| !(cd->c_type->ct_itemdescr->ct_flags & CT_IS_BOOL)) { | |
| 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); | |
| } | |
| else if (cd->c_type->ct_itemdescr->ct_flags & CT_PRIMITIVE_CHAR) { | |
| switch (cd->c_type->ct_itemdescr->ct_size) { | |
| case 2: { | |
| const cffi_char16_t *start = (cffi_char16_t *)cd->c_data; | |
| if (length < 0) { | |
| /*READ(start, 2)*/ | |
| length = 0; | |
| while (start[length]) | |
| length++; | |
| /*READ(start, 2 * length)*/ | |
| } | |
| else { | |
| /*READ(start, 2 * length)*/ | |
| maxlen = length; | |
| length = 0; | |
| while (length < maxlen && start[length]) | |
| length++; | |
| } | |
| return _my_PyUnicode_FromChar16(start, length); | |
| } | |
| case 4: { | |
| const cffi_char32_t *start = (cffi_char32_t *)cd->c_data; | |
| if (length < 0) { | |
| /*READ(start, 4)*/ | |
| length = 0; | |
| while (start[length]) | |
| length++; | |
| /*READ(start, 4 * length)*/ | |
| } | |
| else { | |
| /*READ(start, 4 * length)*/ | |
| maxlen = length; | |
| length = 0; | |
| while (length < maxlen && start[length]) | |
| length++; | |
| } | |
| return _my_PyUnicode_FromChar32(start, length); | |
| } | |
| } | |
| } | |
| } | |
| 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); | |
| else if (cd->c_type->ct_flags & CT_PRIMITIVE_CHAR) { | |
| switch (cd->c_type->ct_size) { | |
| case 2: | |
| return _my_PyUnicode_FromChar16((cffi_char16_t *)cd->c_data, 1); | |
| case 4: | |
| return _my_PyUnicode_FromChar32((cffi_char32_t *)cd->c_data, 1); | |
| } | |
| } | |
| } | |
| PyErr_Format(PyExc_TypeError, "string(): unexpected cdata '%s' argument", | |
| cd->c_type->ct_name); | |
| return NULL; | |
| } | |
| static PyObject *b_unpack(PyObject *self, PyObject *args, PyObject *kwds) | |
| { | |
| CDataObject *cd; | |
| CTypeDescrObject *ctitem; | |
| Py_ssize_t i, length, itemsize; | |
| PyObject *result; | |
| char *src; | |
| int casenum; | |
| static char *keywords[] = {"cdata", "length", NULL}; | |
| if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!n:unpack", keywords, | |
| &CData_Type, &cd, &length)) | |
| return NULL; | |
| if (!(cd->c_type->ct_flags & (CT_ARRAY|CT_POINTER))) { | |
| PyErr_Format(PyExc_TypeError, | |
| "expected a pointer or array, got '%s'", | |
| cd->c_type->ct_name); | |
| return NULL; | |
| } | |
| if (length < 0) { | |
| PyErr_SetString(PyExc_ValueError, "'length' cannot be negative"); | |
| return NULL; | |
| } | |
| if (cd->c_data == NULL) { | |
| PyObject *s = cdata_repr(cd); | |
| if (s != NULL) { | |
| PyErr_Format(PyExc_RuntimeError, | |
| "cannot use unpack() on %s", | |
| PyText_AS_UTF8(s)); | |
| Py_DECREF(s); | |
| } | |
| return NULL; | |
| } | |
| /* byte- and unicode strings */ | |
| ctitem = cd->c_type->ct_itemdescr; | |
| if (ctitem->ct_flags & CT_PRIMITIVE_CHAR) { | |
| switch (ctitem->ct_size) { | |
| case sizeof(char): | |
| return PyBytes_FromStringAndSize(cd->c_data, length); | |
| case 2: | |
| return _my_PyUnicode_FromChar16((cffi_char16_t *)cd->c_data,length); | |
| case 4: | |
| return _my_PyUnicode_FromChar32((cffi_char32_t *)cd->c_data,length); | |
| } | |
| } | |
| /* else, the result is a list. This implementation should be | |
| equivalent to but much faster than '[p[i] for i in range(length)]'. | |
| (Note that on PyPy, 'list(p[0:length])' should be equally fast, | |
| but arguably, finding out that there *is* such an unexpected way | |
| to write things down is the real problem.) | |
| */ | |
| result = PyList_New(length); | |
| if (result == NULL) | |
| return NULL; | |
| src = cd->c_data; | |
| itemsize = ctitem->ct_size; | |
| if (itemsize < 0) { | |
| Py_DECREF(result); | |
| PyErr_Format(PyExc_ValueError, "'%s' points to items of unknown size", | |
| cd->c_type->ct_name); | |
| return NULL; | |
| } | |
| /* Determine some common fast-paths for the loop below. The case -1 | |
| is the fall-back, which always gives the right answer. */ | |
| #define ALIGNMENT_CHECK(align) \ | |
| (((align) & ((align) - 1)) == 0 && \ | |
| (((uintptr_t)src) & ((align) - 1)) == 0) | |
| casenum = -1; | |
| if ((ctitem->ct_flags & CT_PRIMITIVE_ANY) && | |
| ALIGNMENT_CHECK(ctitem->ct_length)) { | |
| /* Source data is fully aligned; we can directly read without | |
| memcpy(). The unaligned case is expected to be rare; in | |
| this situation it is ok to fall back to the general | |
| convert_to_object() in the loop. For now we also use this | |
| fall-back for types that are too large. | |
| */ | |
| if (ctitem->ct_flags & CT_PRIMITIVE_SIGNED) { | |
| if (itemsize == sizeof(long)) casenum = 3; | |
| else if (itemsize == sizeof(int)) casenum = 2; | |
| else if (itemsize == sizeof(short)) casenum = 1; | |
| else if (itemsize == sizeof(signed char)) casenum = 0; | |
| } | |
| else if (ctitem->ct_flags & CT_PRIMITIVE_UNSIGNED) { | |
| /* Note: we never pick case 6 if sizeof(int) == sizeof(long), | |
| so that case 6 below can assume that the 'unsigned int' result | |
| would always fit in a 'signed long'. */ | |
| if (ctitem->ct_flags & CT_IS_BOOL) casenum = 11; | |
| else if (itemsize == sizeof(unsigned long)) casenum = 7; | |
| else if (itemsize == sizeof(unsigned int)) casenum = 6; | |
| else if (itemsize == sizeof(unsigned short)) casenum = 5; | |
| else if (itemsize == sizeof(unsigned char)) casenum = 4; | |
| } | |
| else if (ctitem->ct_flags & CT_PRIMITIVE_FLOAT) { | |
| if (itemsize == sizeof(double)) casenum = 9; | |
| else if (itemsize == sizeof(float)) casenum = 8; | |
| } | |
| } | |
| else if (ctitem->ct_flags & (CT_POINTER | CT_FUNCTIONPTR)) { | |
| casenum = 10; /* any pointer */ | |
| } | |
| #undef ALIGNMENT_CHECK | |
| for (i = 0; i < length; i++) { | |
| PyObject *x; | |
| switch (casenum) { | |
| /* general case */ | |
| default: x = convert_to_object(src, ctitem); break; | |
| /* special cases for performance only */ | |
| case 0: x = PyInt_FromLong(*(signed char *)src); break; | |
| case 1: x = PyInt_FromLong(*(short *)src); break; | |
| case 2: x = PyInt_FromLong(*(int *)src); break; | |
| case 3: x = PyInt_FromLong(*(long *)src); break; | |
| case 4: x = PyInt_FromLong(*(unsigned char *)src); break; | |
| case 5: x = PyInt_FromLong(*(unsigned short *)src); break; | |
| case 6: x = PyInt_FromLong((long)*(unsigned int *)src); break; | |
| case 7: x = PyLong_FromUnsignedLong(*(unsigned long *)src); break; | |
| case 8: x = PyFloat_FromDouble(*(float *)src); break; | |
| case 9: x = PyFloat_FromDouble(*(double *)src); break; | |
| case 10: x = new_simple_cdata(*(char **)src, ctitem); break; | |
| case 11: | |
| switch (*(unsigned char *)src) { | |
| case 0: x = Py_False; Py_INCREF(x); break; | |
| case 1: x = Py_True; Py_INCREF(x); break; | |
| default: x = convert_to_object(src, ctitem); /* error */ | |
| } | |
| break; | |
| } | |
| if (x == NULL) { | |
| Py_DECREF(result); | |
| return NULL; | |
| } | |
| PyList_SET_ITEM(result, i, x); | |
| src += itemsize; | |
| } | |
| return result; | |
| } | |
| static PyObject * | |
| b_buffer_new(PyTypeObject *type, PyObject *args, PyObject *kwds) | |
| { | |
| /* this is the constructor of the type implemented in minibuffer.h */ | |
| CDataObject *cd; | |
| Py_ssize_t size = -1; | |
| static char *keywords[] = {"cdata", "size", NULL}; | |
| if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|n:buffer", keywords, | |
| &CData_Type, &cd, &size)) | |
| return NULL; | |
| if (size < 0) | |
| size = _cdata_var_byte_size(cd); | |
| 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 *arg) | |
| { | |
| long ival = PyInt_AsLong(arg); | |
| if (ival == -1 && PyErr_Occurred()) | |
| return NULL; | |
| else if (ival < INT_MIN || ival > INT_MAX) { | |
| PyErr_SetString(PyExc_OverflowError, "errno value too large"); | |
| return NULL; | |
| } | |
| errno = (int)ival; | |
| save_errno_only(); | |
| errno = 0; | |
| Py_INCREF(Py_None); | |
| return Py_None; | |
| } | |
| static PyObject *newp_handle(CTypeDescrObject *ct_voidp, PyObject *x) | |
| { | |
| CDataObject_own_structptr *cd; | |
| cd = (CDataObject_own_structptr *)PyObject_GC_New(CDataObject_own_structptr, | |
| &CDataOwningGC_Type); | |
| if (cd == NULL) | |
| return NULL; | |
| Py_INCREF(ct_voidp); /* must be "void *" */ | |
| cd->head.c_type = ct_voidp; | |
| cd->head.c_data = (char *)cd; | |
| cd->head.c_weakreflist = NULL; | |
| Py_INCREF(x); | |
| cd->structobj = x; | |
| PyObject_GC_Track(cd); | |
| return (PyObject *)cd; | |
| } | |
| static PyObject *b_newp_handle(PyObject *self, PyObject *args) | |
| { | |
| CTypeDescrObject *ct; | |
| 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; | |
| } | |
| return newp_handle(ct, x); | |
| } | |
| static PyObject *b_from_handle(PyObject *self, PyObject *arg) | |
| { | |
| CTypeDescrObject *ct; | |
| CDataObject_own_structptr *orgcd; | |
| PyObject *x; | |
| if (!CData_Check(arg)) { | |
| PyErr_SetString(PyExc_TypeError, "expected a 'cdata' object"); | |
| return NULL; | |
| } | |
| ct = ((CDataObject *)arg)->c_type; | |
| if (!(ct->ct_flags & CT_IS_VOIDCHAR_PTR)) { | |
| PyErr_Format(PyExc_TypeError, | |
| "expected a 'cdata' object with a 'void *' out of " | |
| "new_handle(), got '%s'", ct->ct_name); | |
| return NULL; | |
| } | |
| orgcd = (CDataObject_own_structptr *)((CDataObject *)arg)->c_data; | |
| if (!orgcd) { | |
| PyErr_SetString(PyExc_RuntimeError, | |
| "cannot use from_handle() on NULL pointer"); | |
| return NULL; | |
| } | |
| if (Py_REFCNT(orgcd) <= 0 || Py_TYPE(orgcd) != &CDataOwningGC_Type) { | |
| Py_FatalError("ffi.from_handle() detected that the address passed " | |
| "points to garbage. If it is really the result of " | |
| "ffi.new_handle(), then the Python object has already " | |
| "been garbage collected"); | |
| } | |
| x = orgcd->structobj; | |
| Py_INCREF(x); | |
| return x; | |
| } | |
| static int _my_PyObject_GetContiguousBuffer(PyObject *x, Py_buffer *view, | |
| int writable_only) | |
| { | |
| #if PY_MAJOR_VERSION < 3 | |
| /* Some objects only support the buffer interface and CPython doesn't | |
| translate it into the memoryview interface, mess. Hack a very | |
| minimal content for 'view'. Don't care if the other fields are | |
| uninitialized: we only call PyBuffer_Release(), which only reads | |
| 'view->obj'. */ | |
| PyBufferProcs *pb = x->ob_type->tp_as_buffer; | |
| if (pb && !pb->bf_releasebuffer) { | |
| /* we used to try all three in some vaguely sensible order, | |
| i.e. first the write. But trying to call the write on a | |
| read-only buffer fails with TypeError. So we use a less- | |
| sensible order now. See test_from_buffer_more_cases. | |
| If 'writable_only', we only try bf_getwritebuffer. | |
| */ | |
| readbufferproc proc = NULL; | |
| if (!writable_only) { | |
| proc = (readbufferproc)pb->bf_getreadbuffer; | |
| if (!proc) | |
| proc = (readbufferproc)pb->bf_getcharbuffer; | |
| } | |
| if (!proc) | |
| proc = (readbufferproc)pb->bf_getwritebuffer; | |
| if (proc && pb->bf_getsegcount) { | |
| if ((*pb->bf_getsegcount)(x, NULL) != 1) { | |
| PyErr_SetString(PyExc_TypeError, | |
| "expected a single-segment buffer object"); | |
| return -1; | |
| } | |
| view->len = (*proc)(x, 0, &view->buf); | |
| if (view->len < 0) | |
| return -1; | |
| view->obj = x; | |
| Py_INCREF(x); | |
| return 0; | |
| } | |
| } | |
| #endif | |
| if (PyObject_GetBuffer(x, view, writable_only ? PyBUF_WRITABLE | |
| : PyBUF_SIMPLE) < 0) | |
| return -1; | |
| if (!PyBuffer_IsContiguous(view, 'A')) { | |
| PyBuffer_Release(view); | |
| PyErr_SetString(PyExc_TypeError, "contiguous buffer expected"); | |
| return -1; | |
| } | |
| return 0; | |
| } | |
| static PyObject *direct_from_buffer(CTypeDescrObject *ct, PyObject *x, | |
| int require_writable) | |
| { | |
| CDataObject *cd; | |
| Py_buffer *view; | |
| Py_ssize_t arraylength, minimumlength = 0; | |
| if (!(ct->ct_flags & (CT_ARRAY | CT_POINTER))) { | |
| PyErr_Format(PyExc_TypeError, | |
| "expected a pointer or array ctype, got '%s'", | |
| ct->ct_name); | |
| return NULL; | |
| } | |
| /* PyPy 5.7 can obtain buffers for string (python 2) | |
| or bytes (python 3). from_buffer(u"foo") is disallowed. | |
| */ | |
| if (PyUnicode_Check(x)) { | |
| PyErr_SetString(PyExc_TypeError, | |
| "from_buffer() cannot return the address " | |
| "of a unicode object"); | |
| return NULL; | |
| } | |
| view = PyObject_Malloc(sizeof(Py_buffer)); | |
| if (view == NULL) { | |
| PyErr_NoMemory(); | |
| return NULL; | |
| } | |
| if (_my_PyObject_GetContiguousBuffer(x, view, require_writable) < 0) | |
| goto error1; | |
| if (ct->ct_flags & CT_POINTER) | |
| { | |
| arraylength = view->len; /* number of bytes, not used so far */ | |
| } | |
| else { | |
| /* ct->ct_flags & CT_ARRAY */ | |
| if (ct->ct_length >= 0) { | |
| /* it's an array with a fixed length; make sure that the | |
| buffer contains enough bytes. */ | |
| minimumlength = ct->ct_size; | |
| arraylength = ct->ct_length; | |
| } | |
| else { | |
| /* it's an open 'array[]' */ | |
| if (ct->ct_itemdescr->ct_size == 1) { | |
| /* fast path, performance only */ | |
| arraylength = view->len; | |
| } | |
| else if (ct->ct_itemdescr->ct_size > 0) { | |
| /* give it as many items as fit the buffer. Ignore a | |
| partial last element. */ | |
| arraylength = view->len / ct->ct_itemdescr->ct_size; | |
| } | |
| else { | |
| /* it's an array 'empty[]'. Unsupported obscure case: | |
| the problem is that setting the length of the result | |
| to anything large (like SSIZE_T_MAX) is dangerous, | |
| because if someone tries to loop over it, it will | |
| turn effectively into an infinite loop. */ | |
| PyErr_Format(PyExc_ZeroDivisionError, | |
| "from_buffer('%s', ..): the actual length of the array " | |
| "cannot be computed", ct->ct_name); | |
| goto error2; | |
| } | |
| } | |
| } | |
| if (view->len < minimumlength) { | |
| PyErr_Format(PyExc_ValueError, | |
| "buffer is too small (%zd bytes) for '%s' (%zd bytes)", | |
| view->len, ct->ct_name, minimumlength); | |
| goto error2; | |
| } | |
| cd = (CDataObject *)PyObject_GC_New(CDataObject_frombuf, | |
| &CDataFromBuf_Type); | |
| if (cd == NULL) | |
| goto error2; | |
| Py_INCREF(ct); | |
| cd->c_type = ct; | |
| cd->c_data = view->buf; | |
| cd->c_weakreflist = NULL; | |
| ((CDataObject_frombuf *)cd)->length = arraylength; | |
| ((CDataObject_frombuf *)cd)->bufferview = view; | |
| PyObject_GC_Track(cd); | |
| return (PyObject *)cd; | |
| error2: | |
| PyBuffer_Release(view); | |
| error1: | |
| PyObject_Free(view); | |
| return NULL; | |
| } | |
| static PyObject *b_from_buffer(PyObject *self, PyObject *args) | |
| { | |
| CTypeDescrObject *ct; | |
| PyObject *x; | |
| int require_writable = 0; | |
| if (!PyArg_ParseTuple(args, "O!O|i", &CTypeDescr_Type, &ct, &x, | |
| &require_writable)) | |
| return NULL; | |
| return direct_from_buffer(ct, x, require_writable); | |
| } | |
| static int _fetch_as_buffer(PyObject *x, Py_buffer *view, int writable_only) | |
| { | |
| if (CData_Check(x)) { | |
| CTypeDescrObject *ct = ((CDataObject *)x)->c_type; | |
| if (!(ct->ct_flags & (CT_POINTER|CT_ARRAY))) { | |
| PyErr_Format(PyExc_TypeError, | |
| "expected a pointer or array ctype, got '%s'", | |
| ct->ct_name); | |
| return -1; | |
| } | |
| view->buf = ((CDataObject *)x)->c_data; | |
| view->obj = NULL; | |
| return 0; | |
| } | |
| else { | |
| return _my_PyObject_GetContiguousBuffer(x, view, writable_only); | |
| } | |
| } | |
| static PyObject *b_memmove(PyObject *self, PyObject *args, PyObject *kwds) | |
| { | |
| PyObject *dest_obj, *src_obj; | |
| Py_buffer dest_view, src_view; | |
| Py_ssize_t n; | |
| static char *keywords[] = {"dest", "src", "n", NULL}; | |
| if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOn", keywords, | |
| &dest_obj, &src_obj, &n)) | |
| return NULL; | |
| if (n < 0) { | |
| PyErr_SetString(PyExc_ValueError, "negative size"); | |
| return NULL; | |
| } | |
| if (_fetch_as_buffer(src_obj, &src_view, 0) < 0) { | |
| return NULL; | |
| } | |
| if (_fetch_as_buffer(dest_obj, &dest_view, 1) < 0) { | |
| PyBuffer_Release(&src_view); | |
| return NULL; | |
| } | |
| memmove(dest_view.buf, src_view.buf, n); | |
| PyBuffer_Release(&dest_view); | |
| PyBuffer_Release(&src_view); | |
| Py_INCREF(Py_None); | |
| return Py_None; | |
| } | |
| static PyObject *b__get_types(PyObject *self, PyObject *noarg) | |
| { | |
| return PyTuple_Pack(2, (PyObject *)&CData_Type, | |
| (PyObject *)&CTypeDescr_Type); | |
| } | |
| /* forward, in commontypes.c */ | |
| static PyObject *b__get_common_types(PyObject *self, PyObject *arg); | |
| static PyObject *b_gcp(PyObject *self, PyObject *args, PyObject *kwds) | |
| { | |
| CDataObject *cd; | |
| CDataObject *origobj; | |
| PyObject *destructor; | |
| Py_ssize_t ignored; /* for pypy */ | |
| static char *keywords[] = {"cdata", "destructor", "size", NULL}; | |
| if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!O|n:gc", keywords, | |
| &CData_Type, &origobj, &destructor, | |
| &ignored)) | |
| return NULL; | |
| if (destructor == Py_None) { | |
| if (!PyObject_TypeCheck(origobj, &CDataGCP_Type)) { | |
| PyErr_SetString(PyExc_TypeError, | |
| "Can remove destructor only on a object " | |
| "previously returned by ffi.gc()"); | |
| return NULL; | |
| } | |
| Py_CLEAR(((CDataObject_gcp *)origobj)->destructor); | |
| Py_RETURN_NONE; | |
| } | |
| cd = allocate_gcp_object(origobj, origobj->c_type, destructor); | |
| return (PyObject *)cd; | |
| } | |
| static PyObject *b_release(PyObject *self, PyObject *arg) | |
| { | |
| if (!CData_Check(arg)) { | |
| PyErr_SetString(PyExc_TypeError, "expected a 'cdata' object"); | |
| return NULL; | |
| } | |
| return cdata_exit(arg, NULL); | |
| } | |
| /************************************************************/ | |
| 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; i<num; i++) { | |
| int value = va_arg(vargs, int); | |
| if (value == 0) | |
| value = -66666666; | |
| total += value; | |
| } | |
| va_end(vargs); | |
| return total; | |
| } | |
| static struct _testfunc7_s _testfunc10(int n) | |
| { | |
| struct _testfunc7_s result; | |
| result.a1 = n; | |
| result.a2 = n * n; | |
| return result; | |
| } | |
| struct _testfunc11_s { int a1, a2; }; | |
| static struct _testfunc11_s _testfunc11(int n) | |
| { | |
| struct _testfunc11_s result; | |
| result.a1 = n; | |
| result.a2 = n * n; | |
| return result; | |
| } | |
| struct _testfunc12_s { double a1; }; | |
| static struct _testfunc12_s _testfunc12(int n) | |
| { | |
| struct _testfunc12_s result; | |
| result.a1 = n; | |
| return result; | |
| } | |
| struct _testfunc13_s { int a1, a2, a3; }; | |
| static struct _testfunc13_s _testfunc13(int n) | |
| { | |
| struct _testfunc13_s result; | |
| result.a1 = n; | |
| result.a2 = n * n; | |
| result.a3 = n * n * n; | |
| return result; | |
| } | |
| struct _testfunc14_s { float a1; }; | |
| static struct _testfunc14_s _testfunc14(int n) | |
| { | |
| struct _testfunc14_s result; | |
| result.a1 = (float)n; | |
| return result; | |
| } | |
| struct _testfunc15_s { float a1; int a2; }; | |
| static struct _testfunc15_s _testfunc15(int n) | |
| { | |
| struct _testfunc15_s result; | |
| result.a1 = (float)n; | |
| result.a2 = n * n; | |
| return result; | |
| } | |
| struct _testfunc16_s { float a1, a2; }; | |
| static struct _testfunc16_s _testfunc16(int n) | |
| { | |
| struct _testfunc16_s result; | |
| result.a1 = (float)n; | |
| result.a2 = -(float)n; | |
| return result; | |
| } | |
| struct _testfunc17_s { int a1; float a2; }; | |
| static struct _testfunc17_s _testfunc17(int n) | |
| { | |
| struct _testfunc17_s result; | |
| result.a1 = n; | |
| result.a2 = (float)n * (float)n; | |
| return result; | |
| } | |
| static int _testfunc18(struct _testfunc17_s *ptr) | |
| { | |
| return ptr->a1 + (int)ptr->a2; | |
| } | |
| static long double _testfunc19(long double x, int count) | |
| { | |
| int i; | |
| for (i=0; i<count; i++) { | |
| x = 4*x - x*x; | |
| } | |
| return x; | |
| } | |
| static short _testfunc20(struct _testfunc7_s *ptr) | |
| { | |
| return ptr->a1 + 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; | |
| } | |
| #if 0 /* libffi doesn't properly support complexes currently */ | |
| /* also, MSVC might not support _Complex... */ | |
| /* if this is enabled one day, remember to also add _Complex | |
| * arguments in addition to return values. */ | |
| static float _Complex _testfunc24(float a, float b) | |
| { | |
| return a + I*2.0*b; | |
| } | |
| static double _Complex _testfunc25(double a, double b) | |
| { | |
| return a + I*2.0*b; | |
| } | |
| #endif | |
| 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; | |
| #if 0 | |
| case 24: f = &_testfunc24; break; | |
| case 25: f = &_testfunc25; break; | |
| #endif | |
| default: | |
| PyErr_SetNone(PyExc_ValueError); | |
| return NULL; | |
| } | |
| return PyLong_FromVoidPtr(f); | |
| } | |
| #if PY_MAJOR_VERSION < 3 | |
| static Py_ssize_t _test_segcountproc(PyObject *o, Py_ssize_t *ignored) | |
| { | |
| return 1; | |
| } | |
| static Py_ssize_t _test_getreadbuf(PyObject *o, Py_ssize_t i, void **r) | |
| { | |
| static char buf[] = "RDB"; | |
| *r = buf; | |
| return 3; | |
| } | |
| static Py_ssize_t _test_getwritebuf(PyObject *o, Py_ssize_t i, void **r) | |
| { | |
| static char buf[] = "WRB"; | |
| *r = buf; | |
| return 3; | |
| } | |
| static Py_ssize_t _test_getcharbuf(PyObject *o, Py_ssize_t i, char **r) | |
| { | |
| static char buf[] = "CHB"; | |
| *r = buf; | |
| return 3; | |
| } | |
| #endif | |
| static int _test_getbuf(PyObject *self, Py_buffer *view, int flags) | |
| { | |
| static char buf[] = "GTB"; | |
| return PyBuffer_FillInfo(view, self, buf, 3, /*readonly=*/0, flags); | |
| } | |
| static int _test_getbuf_ro(PyObject *self, Py_buffer *view, int flags) | |
| { | |
| static char buf[] = "ROB"; | |
| return PyBuffer_FillInfo(view, self, buf, 3, /*readonly=*/1, flags); | |
| } | |
| static PyObject *b__testbuff(PyObject *self, PyObject *args) | |
| { | |
| /* for testing only */ | |
| int methods; | |
| PyTypeObject *obj; | |
| if (!PyArg_ParseTuple(args, "O!i|_testbuff", &PyType_Type, &obj, &methods)) | |
| return NULL; | |
| assert(obj->tp_as_buffer != NULL); | |
| #if PY_MAJOR_VERSION < 3 | |
| obj->tp_as_buffer->bf_getsegcount = &_test_segcountproc; | |
| obj->tp_flags |= Py_TPFLAGS_HAVE_GETCHARBUFFER; | |
| obj->tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER; | |
| if (methods & 1) obj->tp_as_buffer->bf_getreadbuffer = &_test_getreadbuf; | |
| if (methods & 2) obj->tp_as_buffer->bf_getwritebuffer = &_test_getwritebuf; | |
| if (methods & 4) obj->tp_as_buffer->bf_getcharbuffer = &_test_getcharbuf; | |
| #endif | |
| if (methods & 8) obj->tp_as_buffer->bf_getbuffer = &_test_getbuf; | |
| if (methods & 16) obj->tp_as_buffer->bf_getbuffer = &_test_getbuf_ro; | |
| Py_INCREF(Py_None); | |
| return Py_None; | |
| } | |
| static PyObject *b_init_cffi_1_0_external_module(PyObject *, PyObject *); | |
| /* forward, see cffi1_module.c */ | |
| 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", (PyCFunction)b_string, METH_VARARGS | METH_KEYWORDS}, | |
| {"unpack", (PyCFunction)b_unpack, METH_VARARGS | METH_KEYWORDS}, | |
| {"get_errno", b_get_errno, METH_NOARGS}, | |
| {"set_errno", b_set_errno, METH_O}, | |
| {"newp_handle", b_newp_handle, METH_VARARGS}, | |
| {"from_handle", b_from_handle, METH_O}, | |
| {"from_buffer", b_from_buffer, METH_VARARGS}, | |
| {"memmove", (PyCFunction)b_memmove, METH_VARARGS | METH_KEYWORDS}, | |
| {"gcp", (PyCFunction)b_gcp, METH_VARARGS | METH_KEYWORDS}, | |
| {"release", b_release, METH_O}, | |
| #ifdef MS_WIN32 | |
| {"getwinerror", (PyCFunction)b_getwinerror, METH_VARARGS | METH_KEYWORDS}, | |
| #endif | |
| {"_get_types", b__get_types, METH_NOARGS}, | |
| {"_get_common_types", b__get_common_types, METH_O}, | |
| {"_testfunc", b__testfunc, METH_VARARGS}, | |
| {"_testbuff", b__testbuff, METH_VARARGS}, | |
| {"_init_cffi_1_0_external_module", b_init_cffi_1_0_external_module, METH_O}, | |
| {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)(0ULL-(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); | |
| } | |
| /* backward-compatibility hack: instead of _cffi_to_c_char16_t() and | |
| * _cffi_to_c_char32_t(), we have _cffi_to_c_wchar_t() handling whatever | |
| * size is wchar_t, and _cffi_to_c_wchar3216_t() handling the opposite. | |
| */ | |
| #ifdef HAVE_WCHAR_H | |
| typedef wchar_t cffi_wchar_t; | |
| #else | |
| typedef uint16_t cffi_wchar_t; /* random pick... */ | |
| #endif | |
| static cffi_wchar_t _cffi_to_c_wchar_t(PyObject *init) | |
| { | |
| if (sizeof(cffi_wchar_t) == 2) | |
| return (cffi_wchar_t)_convert_to_char16_t(init); | |
| else | |
| return (cffi_wchar_t)_convert_to_char32_t(init); | |
| } | |
| static PyObject *_cffi_from_c_wchar_t(cffi_wchar_t x) { | |
| if (sizeof(cffi_wchar_t) == 2) { | |
| cffi_char16_t input = x; | |
| return _my_PyUnicode_FromChar16(&input, 1); | |
| } | |
| else { | |
| cffi_char32_t input = x; | |
| return _my_PyUnicode_FromChar32(&input, 1); | |
| } | |
| } | |
| static int _cffi_to_c_wchar3216_t(PyObject *init) | |
| { | |
| if (sizeof(cffi_wchar_t) == 4) | |
| return (int)_convert_to_char16_t(init); | |
| else | |
| return (int)_convert_to_char32_t(init); | |
| } | |
| static PyObject *_cffi_from_c_wchar3216_t(int x) { | |
| if (sizeof(cffi_wchar_t) == 4) { | |
| cffi_char16_t input = x; | |
| return _my_PyUnicode_FromChar16(&input, 1); | |
| } | |
| else { | |
| cffi_char32_t input = x; | |
| return _my_PyUnicode_FromChar32(&input, 1); | |
| } | |
| } | |
| struct _cffi_externpy_s; /* forward declaration */ | |
| static void cffi_call_python(struct _cffi_externpy_s *, char *args); | |
| static void *cffi_exports[] = { | |
| NULL, | |
| _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, | |
| _cffi_to_c_wchar_t, | |
| _cffi_from_c_wchar_t, | |
| _cffi_to_c_long_double, | |
| _cffi_to_c__Bool, | |
| _prepare_pointer_call_argument, | |
| convert_array_from_object, | |
| cffi_call_python, | |
| _cffi_to_c_wchar3216_t, | |
| _cffi_from_c_wchar3216_t, | |
| }; | |
| static struct { const char *name; int value; } all_dlopen_flags[] = { | |
| { "RTLD_LAZY", RTLD_LAZY }, | |
| { "RTLD_NOW", RTLD_NOW }, | |
| { "RTLD_GLOBAL", RTLD_GLOBAL }, | |
| #ifdef RTLD_LOCAL | |
| { "RTLD_LOCAL", RTLD_LOCAL }, | |
| #else | |
| { "RTLD_LOCAL", 0 }, | |
| #endif | |
| #ifdef RTLD_NODELETE | |
| { "RTLD_NODELETE", RTLD_NODELETE }, | |
| #endif | |
| #ifdef RTLD_NOLOAD | |
| { "RTLD_NOLOAD", RTLD_NOLOAD }, | |
| #endif | |
| #ifdef RTLD_DEEPBIND | |
| { "RTLD_DEEPBIND", RTLD_DEEPBIND }, | |
| #endif | |
| { NULL, 0 } | |
| }; | |
| /************************************************************/ | |
| #include "cffi1_module.c" | |
| /************************************************************/ | |
| #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; | |
| int i; | |
| static char init_done = 0; | |
| static PyTypeObject *all_types[] = { | |
| &dl_type, | |
| &CTypeDescr_Type, | |
| &CField_Type, | |
| &CData_Type, | |
| &CDataOwning_Type, | |
| &CDataOwningGC_Type, | |
| &CDataFromBuf_Type, | |
| &CDataGCP_Type, | |
| &CDataIter_Type, | |
| &MiniBuffer_Type, | |
| &FFI_Type, | |
| &Lib_Type, | |
| &GlobSupport_Type, | |
| NULL | |
| }; | |
| 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 (unique_cache == NULL) { | |
| unique_cache = PyDict_New(); | |
| if (unique_cache == NULL) | |
| INITERROR; | |
| } | |
| /* readify all types and add them to the module */ | |
| for (i = 0; all_types[i] != NULL; i++) { | |
| PyTypeObject *tp = all_types[i]; | |
| PyObject *tpo = (PyObject *)tp; | |
| if (strncmp(tp->tp_name, "_cffi_backend.", 14) != 0) { | |
| PyErr_Format(PyExc_ImportError, | |
| "'%s' is an ill-formed type name", tp->tp_name); | |
| INITERROR; | |
| } | |
| if (PyType_Ready(tp) < 0) | |
| INITERROR; | |
| Py_INCREF(tpo); | |
| if (PyModule_AddObject(m, tp->tp_name + 14, tpo) < 0) | |
| INITERROR; | |
| } | |
| if (!init_done) { | |
| v = PyText_FromString("_cffi_backend"); | |
| if (v == NULL || PyDict_SetItemString(CData_Type.tp_dict, | |
| "__module__", v) < 0) | |
| INITERROR; | |
| v = PyText_FromString("<cdata>"); | |
| if (v == NULL || PyDict_SetItemString(CData_Type.tp_dict, | |
| "__name__", v) < 0) | |
| INITERROR; | |
| init_done = 1; | |
| } | |
| /* this is for backward compatibility only */ | |
| v = PyCapsule_New((void *)cffi_exports, "cffi", NULL); | |
| if (v == NULL || PyModule_AddObject(m, "_C_API", v) < 0) | |
| INITERROR; | |
| v = PyText_FromString(CFFI_VERSION); | |
| 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 | |
| PyModule_AddIntConstant(m, "FFI_CDECL", FFI_DEFAULT_ABI) < 0 || | |
| #ifdef MS_WIN32 | |
| # ifdef _WIN64 | |
| PyModule_AddIntConstant(m, "_WIN", 64) < 0 || /* win64 */ | |
| # else | |
| PyModule_AddIntConstant(m, "_WIN", 32) < 0 || /* win32 */ | |
| # endif | |
| #endif | |
| 0) | |
| INITERROR; | |
| for (i = 0; all_dlopen_flags[i].name != NULL; i++) { | |
| if (PyModule_AddIntConstant(m, | |
| all_dlopen_flags[i].name, | |
| all_dlopen_flags[i].value) < 0) | |
| INITERROR; | |
| } | |
| init_cffi_tls(); | |
| if (PyErr_Occurred()) | |
| INITERROR; | |
| init_cffi_tls_zombie(); | |
| if (PyErr_Occurred()) | |
| INITERROR; | |
| if (init_ffi_lib(m) < 0) | |
| INITERROR; | |
| #if PY_MAJOR_VERSION >= 3 | |
| if (init_file_emulator() < 0) | |
| INITERROR; | |
| return m; | |
| #endif | |
| } |