Learn more  » Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Bower components Debian packages RPM packages NuGet packages

aroundthecode / cffi   python

Repository URL to install this package:

/ backend_ctypes.py

import ctypes, ctypes.util, operator, sys
from . import model

if sys.version_info < (3,):
    bytechr = chr
else:
    unicode = str
    long = int
    xrange = range
    bytechr = lambda num: bytes([num])

class CTypesType(type):
    pass

class CTypesData(object):
    __metaclass__ = CTypesType
    __slots__ = ['__weakref__']
    __name__ = '<cdata>'

    def __init__(self, *args):
        raise TypeError("cannot instantiate %r" % (self.__class__,))

    @classmethod
    def _newp(cls, init):
        raise TypeError("expected a pointer or array ctype, got '%s'"
                        % (cls._get_c_name(),))

    @staticmethod
    def _to_ctypes(value):
        raise TypeError

    @classmethod
    def _arg_to_ctypes(cls, *value):
        try:
            ctype = cls._ctype
        except AttributeError:
            raise TypeError("cannot create an instance of %r" % (cls,))
        if value:
            res = cls._to_ctypes(*value)
            if not isinstance(res, ctype):
                res = cls._ctype(res)
        else:
            res = cls._ctype()
        return res

    @classmethod
    def _create_ctype_obj(cls, init):
        if init is None:
            return cls._arg_to_ctypes()
        else:
            return cls._arg_to_ctypes(init)

    @staticmethod
    def _from_ctypes(ctypes_value):
        raise TypeError

    @classmethod
    def _get_c_name(cls, replace_with=''):
        return cls._reftypename.replace(' &', replace_with)

    @classmethod
    def _fix_class(cls):
        cls.__name__ = 'CData<%s>' % (cls._get_c_name(),)
        cls.__qualname__ = 'CData<%s>' % (cls._get_c_name(),)
        cls.__module__ = 'ffi'

    def _get_own_repr(self):
        raise NotImplementedError

    def _addr_repr(self, address):
        if address == 0:
            return 'NULL'
        else:
            if address < 0:
                address += 1 << (8*ctypes.sizeof(ctypes.c_void_p))
            return '0x%x' % address

    def __repr__(self, c_name=None):
        own = self._get_own_repr()
        return '<cdata %r %s>' % (c_name or self._get_c_name(), own)

    def _convert_to_address(self, BClass):
        if BClass is None:
            raise TypeError("cannot convert %r to an address" % (
                self._get_c_name(),))
        else:
            raise TypeError("cannot convert %r to %r" % (
                self._get_c_name(), BClass._get_c_name()))

    @classmethod
    def _get_size(cls):
        return ctypes.sizeof(cls._ctype)

    def _get_size_of_instance(self):
        return ctypes.sizeof(self._ctype)

    @classmethod
    def _cast_from(cls, source):
        raise TypeError("cannot cast to %r" % (cls._get_c_name(),))

    def _cast_to_integer(self):
        return self._convert_to_address(None)

    @classmethod
    def _alignment(cls):
        return ctypes.alignment(cls._ctype)

    def __iter__(self):
        raise TypeError("cdata %r does not support iteration" % (
            self._get_c_name()),)

    def _make_cmp(name):
        cmpfunc = getattr(operator, name)
        def cmp(self, other):
            v_is_ptr = not isinstance(self, CTypesGenericPrimitive)
            w_is_ptr = (isinstance(other, CTypesData) and
                           not isinstance(other, CTypesGenericPrimitive))
            if v_is_ptr and w_is_ptr:
                return cmpfunc(self._convert_to_address(None),
                               other._convert_to_address(None))
            elif v_is_ptr or w_is_ptr:
                return NotImplemented
            else:
                if isinstance(self, CTypesGenericPrimitive):
                    self = self._value
                if isinstance(other, CTypesGenericPrimitive):
                    other = other._value
                return cmpfunc(self, other)
        cmp.func_name = name
        return cmp

    __eq__ = _make_cmp('__eq__')
    __ne__ = _make_cmp('__ne__')
    __lt__ = _make_cmp('__lt__')
    __le__ = _make_cmp('__le__')
    __gt__ = _make_cmp('__gt__')
    __ge__ = _make_cmp('__ge__')

    def __hash__(self):
        return hash(self._convert_to_address(None))

    def _to_string(self, maxlen):
        raise TypeError("string(): %r" % (self,))


class CTypesGenericPrimitive(CTypesData):
    __slots__ = []

    def __hash__(self):
        return hash(self._value)

    def _get_own_repr(self):
        return repr(self._from_ctypes(self._value))


class CTypesGenericArray(CTypesData):
    __slots__ = []

    @classmethod
    def _newp(cls, init):
        return cls(init)

    def __iter__(self):
        for i in xrange(len(self)):
            yield self[i]

    def _get_own_repr(self):
        return self._addr_repr(ctypes.addressof(self._blob))


class CTypesGenericPtr(CTypesData):
    __slots__ = ['_address', '_as_ctype_ptr']
    _automatic_casts = False
    kind = "pointer"

    @classmethod
    def _newp(cls, init):
        return cls(init)

    @classmethod
    def _cast_from(cls, source):
        if source is None:
            address = 0
        elif isinstance(source, CTypesData):
            address = source._cast_to_integer()
        elif isinstance(source, (int, long)):
            address = source
        else:
            raise TypeError("bad type for cast to %r: %r" %
                            (cls, type(source).__name__))
        return cls._new_pointer_at(address)

    @classmethod
    def _new_pointer_at(cls, address):
        self = cls.__new__(cls)
        self._address = address
        self._as_ctype_ptr = ctypes.cast(address, cls._ctype)
        return self

    def _get_own_repr(self):
        try:
            return self._addr_repr(self._address)
        except AttributeError:
            return '???'

    def _cast_to_integer(self):
        return self._address

    def __nonzero__(self):
        return bool(self._address)
    __bool__ = __nonzero__

    @classmethod
    def _to_ctypes(cls, value):
        if not isinstance(value, CTypesData):
            raise TypeError("unexpected %s object" % type(value).__name__)
        address = value._convert_to_address(cls)
        return ctypes.cast(address, cls._ctype)

    @classmethod
    def _from_ctypes(cls, ctypes_ptr):
        address = ctypes.cast(ctypes_ptr, ctypes.c_void_p).value or 0
        return cls._new_pointer_at(address)

    @classmethod
    def _initialize(cls, ctypes_ptr, value):
        if value:
            ctypes_ptr.contents = cls._to_ctypes(value).contents

    def _convert_to_address(self, BClass):
        if (BClass in (self.__class__, None) or BClass._automatic_casts
            or self._automatic_casts):
            return self._address
        else:
            return CTypesData._convert_to_address(self, BClass)


class CTypesBaseStructOrUnion(CTypesData):
    __slots__ = ['_blob']

    @classmethod
    def _create_ctype_obj(cls, init):
        # may be overridden
        raise TypeError("cannot instantiate opaque type %s" % (cls,))

    def _get_own_repr(self):
        return self._addr_repr(ctypes.addressof(self._blob))

    @classmethod
    def _offsetof(cls, fieldname):
        return getattr(cls._ctype, fieldname).offset

    def _convert_to_address(self, BClass):
        if getattr(BClass, '_BItem', None) is self.__class__:
            return ctypes.addressof(self._blob)
        else:
            return CTypesData._convert_to_address(self, BClass)

    @classmethod
    def _from_ctypes(cls, ctypes_struct_or_union):
        self = cls.__new__(cls)
        self._blob = ctypes_struct_or_union
        return self

    @classmethod
    def _to_ctypes(cls, value):
        return value._blob

    def __repr__(self, c_name=None):
        return CTypesData.__repr__(self, c_name or self._get_c_name(' &'))


class CTypesBackend(object):

    PRIMITIVE_TYPES = {
        'char': ctypes.c_char,
        'short': ctypes.c_short,
        'int': ctypes.c_int,
        'long': ctypes.c_long,
        'long long': ctypes.c_longlong,
        'signed char': ctypes.c_byte,
        'unsigned char': ctypes.c_ubyte,
        'unsigned short': ctypes.c_ushort,
        'unsigned int': ctypes.c_uint,
        'unsigned long': ctypes.c_ulong,
        'unsigned long long': ctypes.c_ulonglong,
        'float': ctypes.c_float,
        'double': ctypes.c_double,
        '_Bool': ctypes.c_bool,
        }

    for _name in ['unsigned long long', 'unsigned long',
                  'unsigned int', 'unsigned short', 'unsigned char']:
        _size = ctypes.sizeof(PRIMITIVE_TYPES[_name])
        PRIMITIVE_TYPES['uint%d_t' % (8*_size)] = PRIMITIVE_TYPES[_name]
        if _size == ctypes.sizeof(ctypes.c_void_p):
            PRIMITIVE_TYPES['uintptr_t'] = PRIMITIVE_TYPES[_name]
        if _size == ctypes.sizeof(ctypes.c_size_t):
            PRIMITIVE_TYPES['size_t'] = PRIMITIVE_TYPES[_name]

    for _name in ['long long', 'long', 'int', 'short', 'signed char']:
        _size = ctypes.sizeof(PRIMITIVE_TYPES[_name])
        PRIMITIVE_TYPES['int%d_t' % (8*_size)] = PRIMITIVE_TYPES[_name]
        if _size == ctypes.sizeof(ctypes.c_void_p):
            PRIMITIVE_TYPES['intptr_t'] = PRIMITIVE_TYPES[_name]
            PRIMITIVE_TYPES['ptrdiff_t'] = PRIMITIVE_TYPES[_name]
        if _size == ctypes.sizeof(ctypes.c_size_t):
            PRIMITIVE_TYPES['ssize_t'] = PRIMITIVE_TYPES[_name]


    def __init__(self):
        self.RTLD_LAZY = 0   # not supported anyway by ctypes
        self.RTLD_NOW  = 0
        self.RTLD_GLOBAL = ctypes.RTLD_GLOBAL
        self.RTLD_LOCAL = ctypes.RTLD_LOCAL

    def set_ffi(self, ffi):
        self.ffi = ffi

    def _get_types(self):
        return CTypesData, CTypesType

    def load_library(self, path, flags=0):
        cdll = ctypes.CDLL(path, flags)
        return CTypesLibrary(self, cdll)

    def new_void_type(self):
        class CTypesVoid(CTypesData):
            __slots__ = []
            _reftypename = 'void &'
            @staticmethod
            def _from_ctypes(novalue):
                return None
            @staticmethod
            def _to_ctypes(novalue):
                if novalue is not None:
                    raise TypeError("None expected, got %s object" %
                                    (type(novalue).__name__,))
                return None
        CTypesVoid._fix_class()
        return CTypesVoid

    def new_primitive_type(self, name):
        if name == 'wchar_t':
            raise NotImplementedError(name)
Loading ...