Exemplo n.º 1
0
 def test_keepalive_temp_buffer(self):
     """
         DLLEXPORT
         char* do_nothing(char* s)
         {
             return s;
         }
     """
     from _rawffi.alt import CDLL, types
     import _rawffi
     libfoo = CDLL(self.libfoo_name)
     do_nothing = libfoo.getfunc('do_nothing', [types.char_p], types.char_p)
     CharArray = _rawffi.Array('c')
     #
     ptr = do_nothing('foobar')
     array = CharArray.fromaddress(ptr, 7)
     assert list(array) == list('foobar\00')
     do_nothing.free_temp_buffers()
Exemplo n.º 2
0
 def _wrap_result(self, restype, result):
     """
     Convert from low-level repr of the result to the high-level python
     one.
     """
     # hack for performance: if restype is a "simple" primitive type, don't
     # allocate the buffer because it's going to be thrown away immediately
     if self._is_primitive(restype) and not restype._is_pointer_like():
         return result
     #
     shape = restype._ffishape
     if is_struct_shape(shape):
         buf = result
     else:
         buf = _rawffi.Array(shape)(1, autofree=True)
         buf[0] = result
     retval = restype._CData_retval(buf)
     return retval
Exemplo n.º 3
0
    def set_type(self, TP):
        if self._is_abstract():
            raise TypeError('abstract class')
        ffiarray = _rawffi.Array('P')

        def __init__(self, value=None):
            if not hasattr(self, '_buffer'):
                self._buffer = ffiarray(1, autofree=True)
            if value is not None:
                self.contents = value

        def _init_no_arg_(self):
            self._buffer = ffiarray(1, autofree=True)

        self._ffiarray = ffiarray
        self.__init__ = __init__
        self._init_no_arg_ = _init_no_arg_
        self._type_ = TP
Exemplo n.º 4
0
 def test_nested_structures(self):
     import _rawffi
     S1 = _rawffi.Structure([('a', 'i'), ('b', 'P'), ('c', 'c')])
     S = _rawffi.Structure([('x', 'c'), ('s1', (S1, 1))])
     assert S.size == S1.alignment + S1.size
     assert S.alignment == S1.alignment
     assert S.fieldoffset('x') == 0
     assert S.fieldoffset('s1') == S1.alignment
     s = S()
     s.x = b'G'
     raises(TypeError, 's.s1')
     assert s.fieldaddress('s1') == s.buffer + S.fieldoffset('s1')
     s1 = S1.fromaddress(s.fieldaddress('s1'))
     s1.c = b'H'
     rawbuf = _rawffi.Array('c').fromaddress(s.buffer, S.size)
     assert rawbuf[0] == b'G'
     assert rawbuf[S1.alignment + S1.fieldoffset('c')] == b'H'
     s.free()
Exemplo n.º 5
0
 def test_array(self):
     import _rawffi
     lib = _rawffi.CDLL(self.lib_name)
     A = _rawffi.Array('i')
     get_array_elem = lib.ptr('get_array_elem', ['P', 'i'], 'i')
     a = A(10)
     a[8] = 3
     a[7] = 1
     a[6] = 2
     arg1 = a.byptr()
     arg2 = A(1)
     for i, expected in enumerate([0, 0, 0, 0, 0, 0, 2, 1, 3, 0]):
         arg2[0] = i
         res = get_array_elem(arg1, arg2)
         assert res[0] == expected
     arg1.free()
     arg2.free()
     assert a[3] == 0
     a.free()
Exemplo n.º 6
0
 def test_raw_callable(self):
     import _rawffi
     lib = _rawffi.CDLL(self.lib_name)
     get_raw_pointer = lib.ptr('get_raw_pointer', [], 'P')
     ptr = get_raw_pointer()
     rawcall = _rawffi.FuncPtr(ptr[0], ['h', 'h'], 'H')
     A = _rawffi.Array('h')
     arg1 = A(1)
     arg2 = A(1)
     arg1[0] = 1
     arg2[0] = 2
     res = rawcall(arg1, arg2)
     assert res[0] == 3
     arg1.free()
     arg2.free()
     assert rawcall.buffer == ptr[0]
     ptr = rawcall.byptr()
     assert ptr[0] == rawcall.buffer
     ptr.free()
Exemplo n.º 7
0
 def test_wcharp2rawunicode(self):
     import _rawffi
     A = _rawffi.Array('i')
     arg = A(1)
     arg[0] = 0x1234
     u = _rawffi.wcharp2rawunicode(arg.itemaddress(0))
     assert u == u'\u1234'
     u = _rawffi.wcharp2rawunicode(arg.itemaddress(0), 1)
     assert u == u'\u1234'
     arg[0] = -1
     if _rawffi.sizeof('u') == 4:
         raises(ValueError, _rawffi.wcharp2rawunicode, arg.itemaddress(0))
         raises(ValueError, _rawffi.wcharp2rawunicode, arg.itemaddress(0),
                1)
         arg[0] = 0x110000
         raises(ValueError, _rawffi.wcharp2rawunicode, arg.itemaddress(0))
         raises(ValueError, _rawffi.wcharp2rawunicode, arg.itemaddress(0),
                1)
     arg.free()
Exemplo n.º 8
0
    def test_variadic_sum(self):
        import _rawffi
        lib = _rawffi.CDLL(self.lib_name)

        A = _rawffi.Array('l')
        n = A(1)
        arg1 = A(1)
        arg2 = A(1)
        n[0] = 2
        arg1[0] = 3
        arg2[0] = 15
        variadic_sum = lib.ptr('variadic_sum', ['l', 'l', 'l'],
                               'l',
                               variadic_args=2)
        res = variadic_sum(n, arg1, arg2)
        assert res[0] == 3 + 15
        arg1.free()
        arg2.free()
        n.free()
Exemplo n.º 9
0
    def test_buffer(self):
        import _rawffi
        S = _rawffi.Structure((40, 1))
        s = S(autofree=True)
        b = buffer(s)
        assert len(b) == 40
        b[4] = 'X'
        b[:3] = 'ABC'
        assert b[:6] == 'ABC\x00X\x00'

        A = _rawffi.Array('c')
        a = A(10, autofree=True)
        a[3] = 'x'
        b = buffer(a)
        assert len(b) == 10
        assert b[3] == 'x'
        b[6] = 'y'
        assert a[6] == 'y'
        b[3:5] = 'zt'
        assert a[3] == 'z'
        assert a[4] == 't'
Exemplo n.º 10
0
 def test_returning_str(self):
     import _rawffi
     lib = _rawffi.CDLL(self.lib_name)
     char_check = lib.ptr('char_check', ['c', 'c'], 's')
     A = _rawffi.Array('c')
     arg1 = A(1)
     arg2 = A(1)
     arg1[0] = 'y'
     arg2[0] = 'x'
     res = char_check(arg1, arg2)
     assert _rawffi.charp2string(res[0]) == 'xxxxxx'
     assert _rawffi.charp2rawstring(res[0]) == 'xxxxxx'
     assert _rawffi.charp2rawstring(res[0], 3) == 'xxx'
     a = A(6, 'xx\x00\x00xx')
     assert _rawffi.charp2string(a.buffer) == 'xx'
     assert _rawffi.charp2rawstring(a.buffer, 4) == 'xx\x00\x00'
     arg1[0] = 'x'
     arg2[0] = 'y'
     res = char_check(arg1, arg2)
     assert res[0] == 0
     assert _rawffi.charp2string(res[0]) is None
     arg1.free()
     arg2.free()
Exemplo n.º 11
0
 def test_convert_strings_to_char_p(self):
     """
         long mystrlen(char* s)
         {
             long len = 0;
             while(*s++)
                 len++;
             return len;
         }
     """
     from _ffi import CDLL, types
     import _rawffi
     libfoo = CDLL(self.libfoo_name)
     mystrlen = libfoo.getfunc('mystrlen', [types.char_p], types.slong)
     #
     # first, try automatic conversion from a string
     assert mystrlen('foobar') == 6
     # then, try to pass an explicit pointer
     CharArray = _rawffi.Array('c')
     mystr = CharArray(7, 'foobar')
     assert mystrlen(mystr.buffer) == 6
     mystr.free()
     mystrlen.free_temp_buffers()
Exemplo n.º 12
0
    def __new__(self, name, bases, dct):
        try:
            tp = dct['_type_']
        except KeyError:
            for base in bases:
                if hasattr(base, '_type_'):
                    tp = base._type_
                    break
            else:
                raise AttributeError("cannot find _type_ attribute")
        if (not isinstance(tp, str) or
            not len(tp) == 1 or
            tp not in SIMPLE_TYPE_CHARS):
            raise ValueError('%s is not a type character' % (tp))
        default = TP_TO_DEFAULT[tp]
        ffiarray = _rawffi.Array(tp)
        result = type.__new__(self, name, bases, dct)
        result._ffiargshape = tp
        result._ffishape = tp
        result._fficompositesize = None
        result._ffiarray = ffiarray
        if tp == 'z':
            # c_char_p
            from _ctypes import Array, _Pointer

            def _getvalue(self):
                addr = self._buffer[0]
                if addr == 0:
                    return None
                else:
                    return _rawffi.charp2string(addr)

            def _setvalue(self, value):
                if isinstance(value, basestring):
                    if isinstance(value, unicode):
                        value = value.encode(ConvMode.encoding,
                                             ConvMode.errors)
                    #self._objects = value
                    array = _rawffi.Array('c')(len(value)+1, value)
                    value = array.buffer
                    self._objects = {'0': CArgObject(array)}
                elif value is None:
                    value = 0
                self._buffer[0] = value
            result.value = property(_getvalue, _setvalue)
        elif tp == 'Z':
            # c_wchar_p
            from _ctypes import Array, _Pointer, _wstring_at_addr
            def _getvalue(self):
                addr = self._buffer[0]
                if addr == 0:
                    return None
                else:
                    return _wstring_at_addr(addr, -1)

            def _setvalue(self, value):
                if isinstance(value, basestring):
                    if isinstance(value, str):
                        value = value.decode(ConvMode.encoding,
                                             ConvMode.errors)
                    #self._objects = value
                    array = _rawffi.Array('u')(len(value)+1, value)
                    value = array.buffer
                    self._objects = {'0': CArgObject(array)}
                elif value is None:
                    value = 0
                self._buffer[0] = value
            result.value = property(_getvalue, _setvalue)

        elif tp == 'P':
            # c_void_p

            def _getvalue(self):
                addr = self._buffer[0]
                if addr == 0:
                    return None
                return addr

            def _setvalue(self, value):
                if isinstance(value, str):
                    array = _rawffi.Array('c')(len(value)+1, value)
                    value = array.buffer
                    self._objects = {'0': CArgObject(array)}
                elif value is None:
                    value = 0
                self._buffer[0] = value
            result.value = property(_getvalue, _setvalue)            
        
        if tp in 'zZ':
            from _ctypes import Array, _Pointer
            # c_char_p
            def from_param(self, value):
                res = generic_xxx_p_from_param(self, value)
                if res is not None:
                    return res
                if isinstance(value, (Array, _Pointer)):
                    from ctypes import c_char, c_byte, c_wchar
                    if type(value)._type_ in [c_char, c_byte, c_wchar]:
                        return value
                return SimpleType.from_param(self, value)
            result.from_param = classmethod(from_param)
        elif tp == 'P':
            from _ctypes import Array, _Pointer
            # c_void_p
            def from_param(self, value):
                res = generic_xxx_p_from_param(self, value)
                if res is not None:
                    return res
                if isinstance(value, Array):
                    return value
                if isinstance(value, _Pointer):
                    return self.from_address(value._buffer.buffer)
                return SimpleType.from_param(self, value)
            result.from_param = classmethod(from_param)

        elif tp == 'u':
            def _setvalue(self, val):
                if isinstance(val, str):
                    val = val.decode(ConvMode.encoding, ConvMode.errors)
                # possible if we use 'ignore'
                if val:
                    self._buffer[0] = val
            def _getvalue(self):
                return self._buffer[0]
            result.value = property(_getvalue, _setvalue)

        elif tp == 'c':
            def _setvalue(self, val):
                if isinstance(val, unicode):
                    val = val.encode(ConvMode.encoding, ConvMode.errors)
                if val:
                    self._buffer[0] = val
            def _getvalue(self):
                return self._buffer[0]
            result.value = property(_getvalue, _setvalue)

        elif tp == 'O':
            def _setvalue(self, val):
                num = pyobj_container.add(val)
                self._buffer[0] = num
            def _getvalue(self):
                return pyobj_container.get(self._buffer[0])
            result.value = property(_getvalue, _setvalue)

        return result
Exemplo n.º 13
0
 def _subarray(self, fieldtype, name):
     """Return a _rawffi array of length 1 whose address is the same as
     the address of the field 'name' of self."""
     address = self._buffer.fieldaddress(name)
     A = _rawffi.Array(fieldtype._ffishape_)
     return A.fromaddress(address, 1)
Exemplo n.º 14
0
    def __new__(self, name, bases, dct):
        try:
            tp = dct['_type_']
        except KeyError:
            for base in bases:
                if hasattr(base, '_type_'):
                    tp = base._type_
                    break
            else:
                raise AttributeError("cannot find _type_ attribute")
        if (not isinstance(tp, str) or not len(tp) == 1
                or tp not in SIMPLE_TYPE_CHARS):
            raise ValueError('%s is not a type character' % (tp))
        default = TP_TO_DEFAULT[tp]
        ffiarray = _rawffi.Array(tp)
        result = type.__new__(self, name, bases, dct)
        result._ffiargshape = tp
        result._ffishape = tp
        result._fficompositesize = None
        result._ffiarray = ffiarray
        if tp == 'z':
            # c_char_p
            def _getvalue(self):
                addr = self._buffer[0]
                if addr == 0:
                    return None
                else:
                    return _rawffi.charp2string(addr)

            def _setvalue(self, value):
                if isinstance(value, basestring):
                    if isinstance(value, unicode):
                        value = value.encode(ConvMode.encoding,
                                             ConvMode.errors)
                    #self._objects = value
                    array = _rawffi.Array('c')(len(value) + 1, value)
                    self._objects = CArgObject(value, array)
                    value = array.buffer
                elif value is None:
                    value = 0
                self._buffer[0] = value

            result.value = property(_getvalue, _setvalue)
        elif tp == 'Z':
            # c_wchar_p
            def _getvalue(self):
                addr = self._buffer[0]
                if addr == 0:
                    return None
                else:
                    return _rawffi.wcharp2unicode(addr)

            def _setvalue(self, value):
                if isinstance(value, basestring):
                    if isinstance(value, str):
                        value = value.decode(ConvMode.encoding,
                                             ConvMode.errors)
                    #self._objects = value
                    array = _rawffi.Array('u')(len(value) + 1, value)
                    self._objects = CArgObject(value, array)
                    value = array.buffer
                elif value is None:
                    value = 0
                self._buffer[0] = value

            result.value = property(_getvalue, _setvalue)

        elif tp == 'P':
            # c_void_p

            def _getvalue(self):
                addr = self._buffer[0]
                if addr == 0:
                    return None
                return addr

            def _setvalue(self, value):
                if isinstance(value, str):
                    array = _rawffi.Array('c')(len(value) + 1, value)
                    self._objects = CArgObject(value, array)
                    value = array.buffer
                elif value is None:
                    value = 0
                self._buffer[0] = value

            result.value = property(_getvalue, _setvalue)

        elif tp == 'u':

            def _setvalue(self, val):
                if isinstance(val, str):
                    val = val.decode(ConvMode.encoding, ConvMode.errors)
                # possible if we use 'ignore'
                if val:
                    self._buffer[0] = val

            def _getvalue(self):
                return self._buffer[0]

            result.value = property(_getvalue, _setvalue)

        elif tp == 'c':

            def _setvalue(self, val):
                if isinstance(val, unicode):
                    val = val.encode(ConvMode.encoding, ConvMode.errors)
                if val:
                    self._buffer[0] = val

            def _getvalue(self):
                return self._buffer[0]

            result.value = property(_getvalue, _setvalue)

        elif tp == 'O':

            def _setvalue(self, val):
                num = pyobj_container.add(val)
                self._buffer[0] = num

            def _getvalue(self):
                return pyobj_container.get(self._buffer[0])

            result.value = property(_getvalue, _setvalue)

        elif tp == 'X':
            from ctypes import windll
            SysAllocStringLen = windll.oleaut32.SysAllocStringLen
            SysStringLen = windll.oleaut32.SysStringLen
            SysFreeString = windll.oleaut32.SysFreeString

            def _getvalue(self):
                addr = self._buffer[0]
                if addr == 0:
                    return None
                else:
                    size = SysStringLen(addr)
                    return _rawffi.wcharp2rawunicode(addr, size)

            def _setvalue(self, value):
                if isinstance(value, basestring):
                    if isinstance(value, str):
                        value = value.decode(ConvMode.encoding,
                                             ConvMode.errors)
                    array = _rawffi.Array('u')(len(value) + 1, value)
                    value = SysAllocStringLen(array.buffer, len(value))
                elif value is None:
                    value = 0
                if self._buffer[0]:
                    SysFreeString(self._buffer[0])
                self._buffer[0] = value

            result.value = property(_getvalue, _setvalue)

        elif tp == 'v':  # VARIANT_BOOL type

            def _getvalue(self):
                return bool(self._buffer[0])

            def _setvalue(self, value):
                if value:
                    self._buffer[0] = -1  # VARIANT_TRUE
                else:
                    self._buffer[0] = 0  # VARIANT_FALSE

            result.value = property(_getvalue, _setvalue)

        return result
Exemplo n.º 15
0
    def __init__(self, *args):
        self.name = None
        self._objects = {keepalive_key(0): self}
        self._needs_free = True

        # Empty function object -- this is needed for casts
        if not args:
            self._buffer = _rawffi.Array('P')(1)
            return

        argsl = list(args)
        argument = argsl.pop(0)

        # Direct construction from raw address
        if isinstance(argument, (int, long)) and not argsl:
            ffiargs, ffires = self._ffishapes(self._argtypes_, self._restype_)
            self._ptr = _rawffi.FuncPtr(argument, ffiargs, ffires,
                                        self._flags_)
            self._buffer = self._ptr.byptr()
            return

        # A callback into Python
        if callable(argument) and not argsl:
            self.callable = argument
            ffiargs, ffires = self._ffishapes(self._argtypes_, self._restype_)
            if self._restype_ is None:
                ffires = None
            self._ptr = _rawffi.CallbackPtr(
                self._wrap_callable(argument, self.argtypes), ffiargs, ffires,
                self._flags_)
            self._buffer = self._ptr.byptr()
            return

        # Function exported from a shared library
        if isinstance(argument, tuple) and len(argument) == 2:
            import ctypes
            self.name, dll = argument
            if isinstance(dll, str):
                self.dll = ctypes.CDLL(dll)
            else:
                self.dll = dll
            if argsl:
                self.paramflags = argsl.pop(0)
                if argsl:
                    raise TypeError("Unknown constructor %s" % (args, ))
            # We need to check dll anyway
            ptr = self._getfuncptr([], ctypes.c_int)
            self._buffer = ptr.byptr()
            return

        # A COM function call, by index
        if (sys.platform == 'win32' and isinstance(argument, (int, long))
                and argsl):
            ffiargs, ffires = self._ffishapes(self._argtypes_, self._restype_)
            self._com_index = argument + 0x1000
            self.name = argsl.pop(0)
            if argsl:
                self.paramflags = argsl.pop(0)
                if argsl:
                    self._com_iid = argsl.pop(0)
                    if argsl:
                        raise TypeError("Unknown constructor %s" % (args, ))
            return

        raise TypeError("Unknown constructor %s" % (args, ))
Exemplo n.º 16
0
    def __new__(self, name, bases, dct):
        try:
            tp = dct['_type_']
        except KeyError:
            for base in bases:
                if hasattr(base, '_type_'):
                    tp = base._type_
                    break
            else:
                raise AttributeError("cannot find _type_ attribute")
        if tp == 'abstract':
            tp = 'i'
        if (not isinstance(tp, str) or not len(tp) == 1
                or tp not in SIMPLE_TYPE_CHARS):
            raise ValueError('%s is not a type character' % (tp))
        default = TP_TO_DEFAULT[tp]
        ffiarray = _rawffi.Array(tp)
        result = type.__new__(self, name, bases, dct)
        result._ffiargshape_ = tp
        result._ffishape_ = tp
        result._fficompositesize_ = None
        result._ffiarray = ffiarray
        if tp in CTYPES_TO_PEP3118_TABLE:
            pep_code = CTYPES_TO_PEP3118_TABLE[tp][_rawffi.sizeof(tp)]
        else:
            pep_code = tp
        result._format = byteorder[sys.byteorder] + pep_code
        if tp == 'z':
            # c_char_p
            def _getvalue(self):
                addr = self._buffer[0]
                if addr == 0:
                    return None
                else:
                    return _rawffi.charp2string(addr)

            def _setvalue(self, value):
                if isinstance(value, basestring):
                    if isinstance(value, unicode):
                        value = value.encode(ConvMode.encoding,
                                             ConvMode.errors)
                    #self._objects = value
                    array = _rawffi.Array('c')(len(value) + 1, value)
                    self._objects = CArgObject(value, array)
                    value = array.buffer
                elif value is None:
                    value = 0
                self._buffer[0] = value

            result.value = property(_getvalue, _setvalue)
            result._ffiargtype = _ffi.types.Pointer(_ffi.types.char)

        elif tp == 'Z':
            # c_wchar_p
            def _getvalue(self):
                addr = self._buffer[0]
                if addr == 0:
                    return None
                else:
                    return _rawffi.wcharp2unicode(addr)

            def _setvalue(self, value):
                if isinstance(value, basestring):
                    if isinstance(value, str):
                        value = value.decode(ConvMode.encoding,
                                             ConvMode.errors)
                    #self._objects = value
                    array = _rawffi.Array('u')(len(value) + 1, value)
                    self._objects = CArgObject(value, array)
                    value = array.buffer
                elif value is None:
                    value = 0
                self._buffer[0] = value

            result.value = property(_getvalue, _setvalue)
            result._ffiargtype = _ffi.types.Pointer(_ffi.types.unichar)

        elif tp == 'P':
            # c_void_p

            def _getvalue(self):
                addr = self._buffer[0]
                if addr == 0:
                    return None
                return addr

            def _setvalue(self, value):
                if isinstance(value, str):
                    array = _rawffi.Array('c')(len(value) + 1, value)
                    self._objects = CArgObject(value, array)
                    value = array.buffer
                elif value is None:
                    value = 0
                self._buffer[0] = value

            result.value = property(_getvalue, _setvalue)

        elif tp == 'u':

            def _setvalue(self, val):
                if isinstance(val, str):
                    val = val.decode(ConvMode.encoding, ConvMode.errors)
                # possible if we use 'ignore'
                if val:
                    self._buffer[0] = val

            def _getvalue(self):
                return self._buffer[0]

            result.value = property(_getvalue, _setvalue)

        elif tp == 'c':

            def _setvalue(self, val):
                if isinstance(val, unicode):
                    val = val.encode(ConvMode.encoding, ConvMode.errors)
                if val:
                    self._buffer[0] = val

            def _getvalue(self):
                return self._buffer[0]

            result.value = property(_getvalue, _setvalue)

        elif tp == 'O':

            def _setvalue(self, val):
                num = pyobj_container.add(val)
                self._buffer[0] = num

            def _getvalue(self):
                return pyobj_container.get(self._buffer[0])

            result.value = property(_getvalue, _setvalue)

        elif tp == 'X':
            from ctypes import WinDLL
            # Use WinDLL("oleaut32") instead of windll.oleaut32
            # because the latter is a shared (cached) object; and
            # other code may set their own restypes. We need out own
            # restype here.
            oleaut32 = WinDLL("oleaut32")
            SysAllocStringLen = oleaut32.SysAllocStringLen
            SysStringLen = oleaut32.SysStringLen
            SysFreeString = oleaut32.SysFreeString

            def _getvalue(self):
                addr = self._buffer[0]
                if addr == 0:
                    return None
                else:
                    size = SysStringLen(addr)
                    return _rawffi.wcharp2rawunicode(addr, size)

            def _setvalue(self, value):
                if isinstance(value, basestring):
                    if isinstance(value, str):
                        value = value.decode(ConvMode.encoding,
                                             ConvMode.errors)
                    array = _rawffi.Array('u')(len(value) + 1, value)
                    value = SysAllocStringLen(array.buffer, len(value))
                elif value is None:
                    value = 0
                if self._buffer[0]:
                    SysFreeString(self._buffer[0])
                self._buffer[0] = value

            result.value = property(_getvalue, _setvalue)

        elif tp == '?':  # regular bool

            def _getvalue(self):
                return bool(self._buffer[0])

            def _setvalue(self, value):
                self._buffer[0] = bool(value)

            result.value = property(_getvalue, _setvalue)

        elif tp == 'v':  # VARIANT_BOOL type

            def _getvalue(self):
                return bool(self._buffer[0])

            def _setvalue(self, value):
                if value:
                    self._buffer[0] = -1  # VARIANT_TRUE
                else:
                    self._buffer[0] = 0  # VARIANT_FALSE

            result.value = property(_getvalue, _setvalue)

        # make pointer-types compatible with the _ffi fast path
        if result._is_pointer_like():

            def _as_ffi_pointer_(self, ffitype):
                return as_ffi_pointer(self, ffitype)

            result._as_ffi_pointer_ = _as_ffi_pointer_
        if name[-2:] != '_p' and name[-3:] not in ('_le', '_be') \
                and name not in ('c_wchar', '_SimpleCData', 'c_longdouble', 'c_bool', 'py_object'):
            if sys.byteorder == 'big':
                name += '_le'
                swapped = self.__new__(self, name, bases, dct)
                result.__ctype_le__ = swapped
                result.__ctype_be__ = result
                swapped.__ctype_be__ = result
                swapped.__ctype_le__ = swapped
                swapped._format = '<' + pep_code
            else:
                name += '_be'
                swapped = self.__new__(self, name, bases, dct)
                result.__ctype_be__ = swapped
                result.__ctype_le__ = result
                swapped.__ctype_le__ = result
                swapped.__ctype_be__ = swapped
                swapped._format = '>' + pep_code
            from _ctypes import sizeof

            def _getval(self):
                return swap_bytes(self._buffer[0], sizeof(self), name, 'get')

            def _setval(self, value):
                d = result()
                d.value = value
                self._buffer[0] = swap_bytes(d.value, sizeof(self), name,
                                             'set')

            swapped.value = property(_getval, _setval)

        return result
Exemplo n.º 17
0
class CFuncPtr(_CData):
    __metaclass__ = CFuncPtrType

    _argtypes_ = None
    _restype_ = None
    _flags_ = 0
    _ffiargshape = 'P'
    _ffishape = 'P'
    _fficompositesize = None
    _ffiarray = _rawffi.Array('P')
    _needs_free = False
    callable = None
    _ptr = None
    _buffer = None
    # win32 COM properties
    _paramflags = None
    _com_index = None
    _com_iid = None

    def _getargtypes(self):
        return self._argtypes_

    def _setargtypes(self, argtypes):
        self._ptr = None
        self._argtypes_ = argtypes

    argtypes = property(_getargtypes, _setargtypes)

    def _getrestype(self):
        return self._restype_

    def _setrestype(self, restype):
        self._ptr = None
        from ctypes import c_char_p
        if restype is int:
            from ctypes import c_int
            restype = c_int
        if not isinstance(restype, _CDataMeta) and not restype is None and \
               not callable(restype):
            raise TypeError("Expected ctypes type, got %s" % (restype, ))
        self._restype_ = restype

    def _delrestype(self):
        self._ptr = None
        del self._restype_

    restype = property(_getrestype, _setrestype, _delrestype)

    def _ffishapes(self, args, restype):
        argtypes = [arg._ffiargshape for arg in args]
        if restype is not None:
            restype = restype._ffiargshape
        else:
            restype = 'O'  # void
        return argtypes, restype

    def __init__(self, *args):
        self.name = None
        self._objects = {keepalive_key(0): self}
        self._needs_free = True
        argument = None
        if len(args) == 1:
            argument = args[0]

        if isinstance(argument, (int, long)):
            # direct construction from raw address
            ffiargs, ffires = self._ffishapes(self._argtypes_, self._restype_)
            self._ptr = _rawffi.FuncPtr(argument, ffiargs, ffires,
                                        self._flags_)
            self._buffer = self._ptr.byptr()
        elif callable(argument):
            # A callback into python
            self.callable = argument
            ffiargs, ffires = self._ffishapes(self._argtypes_, self._restype_)
            self._ptr = _rawffi.CallbackPtr(
                self._wrap_callable(argument, self.argtypes), ffiargs, ffires,
                self._flags_)
            self._buffer = self._ptr.byptr()
        elif isinstance(argument, tuple) and len(argument) == 2:
            # function exported from a shared library
            import ctypes
            self.name, self.dll = argument
            if isinstance(self.dll, str):
                self.dll = ctypes.CDLL(self.dll)
            # we need to check dll anyway
            ptr = self._getfuncptr([], ctypes.c_int)
            self._buffer = ptr.byptr()

        elif (sys.platform == 'win32' and len(args) >= 2
              and isinstance(args[0], (int, long))):
            # A COM function call, by index
            ffiargs, ffires = self._ffishapes(self._argtypes_, self._restype_)
            self._com_index = args[0] + 0x1000
            self.name = args[1]
            if len(args) > 2:
                self._paramflags = args[2]
            # XXX ignored iid = args[3]

        elif len(args) == 0:
            # Empty function object.
            # this is needed for casts
            self._buffer = _rawffi.Array('P')(1)
            return
        else:
            raise TypeError("Unknown constructor %s" % (args, ))

    def _wrap_callable(self, to_call, argtypes):
        def f(*args):
            if argtypes:
                args = [
                    argtype._CData_retval(argtype.from_address(arg)._buffer)
                    for argtype, arg in zip(argtypes, args)
                ]
            return to_call(*args)

        return f

    def __call__(self, *args):
        if self.callable is not None:
            try:
                res = self.callable(*args)
            except:
                exc_info = sys.exc_info()
                traceback.print_tb(exc_info[2], file=sys.stderr)
                print >> sys.stderr, "%s: %s" % (exc_info[0].__name__,
                                                 exc_info[1])
                return 0
            if self._restype_ is not None:
                return res
            return
        argtypes = self._argtypes_

        if self._com_index:
            from ctypes import cast, c_void_p, POINTER
            thisarg = cast(args[0], POINTER(POINTER(c_void_p))).contents
            argtypes = [c_void_p] + list(argtypes)
            args = list(args)
            args[0] = args[0].value
        else:
            thisarg = None

        if argtypes is None:
            argtypes = self._guess_argtypes(args)
        argtypes, argsandobjs = self._wrap_args(argtypes, args)

        restype = self._restype_
        funcptr = self._getfuncptr(argtypes, restype, thisarg)
        resbuffer = funcptr(*[arg._buffer for _, arg in argsandobjs])
        return self._build_result(restype, resbuffer, argtypes, argsandobjs)

    def _getfuncptr(self, argtypes, restype, thisarg=None):
        if self._ptr is not None:
            return self._ptr
        if restype is None or not isinstance(restype, _CDataMeta):
            import ctypes
            restype = ctypes.c_int
        argshapes = [arg._ffiargshape for arg in argtypes]
        resshape = restype._ffiargshape
        if self._buffer is not None:
            ptr = _rawffi.FuncPtr(self._buffer[0], argshapes, resshape,
                                  self._flags_)
            if argtypes is self._argtypes_:
                self._ptr = ptr
            return ptr

        if self._com_index:
            # extract the address from the object's virtual table
            if not thisarg:
                raise ValueError("COM method call without VTable")
            ptr = thisarg[self._com_index - 0x1000]
            return _rawffi.FuncPtr(ptr, argshapes, resshape, self._flags_)

        cdll = self.dll._handle
        try:
            return cdll.ptr(self.name, argshapes, resshape, self._flags_)
        except AttributeError:
            if self._flags_ & _rawffi.FUNCFLAG_CDECL:
                raise

            # For stdcall, try mangled names:
            # funcname -> _funcname@<n>
            # where n is 0, 4, 8, 12, ..., 128
            for i in range(33):
                mangled_name = "_%s@%d" % (self.name, i * 4)
                try:
                    return cdll.ptr(mangled_name, argshapes, resshape,
                                    self._flags_)
                except AttributeError:
                    pass
            raise

    @staticmethod
    def _guess_argtypes(args):
        from _ctypes import _CData
        from ctypes import c_char_p, c_wchar_p, c_void_p, c_int
        from ctypes import Array, Structure
        res = []
        for arg in args:
            if hasattr(arg, '_as_parameter_'):
                arg = arg._as_parameter_
            if isinstance(arg, str):
                res.append(c_char_p)
            elif isinstance(arg, unicode):
                res.append(c_wchar_p)
            elif isinstance(arg, _CData):
                res.append(type(arg))
            elif arg is None:
                res.append(c_void_p)
            #elif arg == 0:
            #    res.append(c_void_p)
            elif isinstance(arg, (int, long)):
                res.append(c_int)
            else:
                raise TypeError("Don't know how to handle %s" % (arg, ))
        return res

    def _wrap_args(self, argtypes, args):
        wrapped_args = []
        consumed = 0
        for i, argtype in enumerate(argtypes):
            defaultvalue = None
            if i > 0 and self._paramflags is not None:
                paramflag = self._paramflags[i - 1]
                if len(paramflag) == 2:
                    idlflag, name = paramflag
                elif len(paramflag) == 3:
                    idlflag, name, defaultvalue = paramflag
                else:
                    idlflag = 0
                idlflag &= (PARAMFLAG_FIN | PARAMFLAG_FOUT | PARAMFLAG_FLCID)

                if idlflag in (0, PARAMFLAG_FIN):
                    pass
                elif idlflag == PARAMFLAG_FOUT:
                    import ctypes
                    val = argtype._type_()
                    wrapped = (val, ctypes.byref(val))
                    wrapped_args.append(wrapped)
                    continue
                elif idlflag == PARAMFLAG_FIN | PARAMFLAG_FLCID:
                    # Always taken from defaultvalue if given,
                    # else the integer 0.
                    val = defaultvalue
                    if val is None:
                        val = 0
                    wrapped = argtype._CData_input(val)
                    wrapped_args.append(wrapped)
                    continue
                else:
                    raise NotImplementedError("paramflags = %s" %
                                              (self._paramflags[i - 1], ))

            if consumed < len(args):
                arg = args[consumed]
            elif defaultvalue is not None:
                arg = defaultvalue
            else:
                raise TypeError("Not enough arguments")

            try:
                wrapped = argtype._CData_input(arg)
            except (UnicodeError, TypeError), e:
                raise ArgumentError(str(e))
            wrapped_args.append(wrapped)
            consumed += 1

        if len(wrapped_args) < len(args):
            extra = args[len(wrapped_args):]
            extra_types = self._guess_argtypes(extra)
            for arg, argtype in zip(extra, extra_types):
                try:
                    wrapped = argtype._CData_input(arg)
                except (UnicodeError, TypeError), e:
                    raise ArgumentError(str(e))
                wrapped_args.append(wrapped)
            argtypes = list(argtypes) + extra_types
Exemplo n.º 18
0
    def __new__(self, name, cls, typedict):
        res = type.__new__(self, name, cls, typedict)
        if '_type_' in typedict:
            ffiarray = _rawffi.Array(typedict['_type_']._ffishape_)
            res._ffiarray = ffiarray
            subletter = getattr(typedict['_type_'], '_type_', None)
            if subletter == 'c':

                def getvalue(self):
                    return _rawffi.charp2string(self._buffer.buffer,
                                                self._length_)

                def setvalue(self, val):
                    # we don't want to have buffers here
                    if len(val) > self._length_:
                        raise ValueError("%r too long" % (val, ))
                    if isinstance(val, str):
                        _rawffi.rawstring2charp(self._buffer.buffer, val)
                    else:
                        for i in range(len(val)):
                            self[i] = val[i]
                    if len(val) < self._length_:
                        self._buffer[len(val)] = '\x00'

                res.value = property(getvalue, setvalue)

                def getraw(self):
                    return _rawffi.charp2rawstring(self._buffer.buffer,
                                                   self._length_)

                def setraw(self, buffer):
                    if len(buffer) > self._length_:
                        raise ValueError("%r too long" % (buffer, ))
                    _rawffi.rawstring2charp(self._buffer.buffer, buffer)

                res.raw = property(getraw, setraw)
            elif subletter == 'u':

                def getvalue(self):
                    return _rawffi.wcharp2unicode(self._buffer.buffer,
                                                  self._length_)

                def setvalue(self, val):
                    # we don't want to have buffers here
                    if len(val) > self._length_:
                        raise ValueError("%r too long" % (val, ))
                    if isinstance(val, unicode):
                        target = self._buffer
                    else:
                        target = self
                    for i in range(len(val)):
                        target[i] = val[i]
                    if len(val) < self._length_:
                        target[len(val)] = u'\x00'

                res.value = property(getvalue, setvalue)

            if '_length_' in typedict:
                res._ffishape_ = (ffiarray, typedict['_length_'])
                res._fficompositesize_ = res._sizeofinstances()
        else:
            res._ffiarray = None
        return res
Exemplo n.º 19
0
class CFuncPtr(_CData):
    __metaclass__ = CFuncPtrType

    _argtypes_ = None
    _restype_ = None
    _errcheck_ = None
    _flags_ = 0
    _ffiargshape = 'P'
    _ffishape = 'P'
    _fficompositesize = None
    _ffiarray = _rawffi.Array('P')
    _needs_free = False
    callable = None
    _ptr = None
    _buffer = None
    # win32 COM properties
    _paramflags = None
    _com_index = None
    _com_iid = None

    __restype_set = False

    def _getargtypes(self):
        return self._argtypes_

    def _setargtypes(self, argtypes):
        self._ptr = None
        if argtypes is None:
            self._argtypes_ = ()
        else:
            for i, argtype in enumerate(argtypes):
                if not hasattr(argtype, 'from_param'):
                    raise TypeError(
                        "item %d in _argtypes_ has no from_param method" %
                        (i + 1, ))
            self._argtypes_ = argtypes

    argtypes = property(_getargtypes, _setargtypes)

    def _getparamflags(self):
        return self._paramflags

    def _setparamflags(self, paramflags):
        if paramflags is None or not self._argtypes_:
            self._paramflags = None
            return
        if not isinstance(paramflags, tuple):
            raise TypeError("paramflags must be a tuple or None")
        if len(paramflags) != len(self._argtypes_):
            raise ValueError(
                "paramflags must have the same length as argtypes")
        for idx, paramflag in enumerate(paramflags):
            paramlen = len(paramflag)
            name = default = None
            if paramlen == 1:
                flag = paramflag[0]
            elif paramlen == 2:
                flag, name = paramflag
            elif paramlen == 3:
                flag, name, default = paramflag
            else:
                raise TypeError(
                    "paramflags must be a sequence of (int [,string [,value]]) "
                    "tuples")
            if not isinstance(flag, int):
                raise TypeError(
                    "paramflags must be a sequence of (int [,string [,value]]) "
                    "tuples")
            _flag = flag & PARAMFLAG_COMBINED
            if _flag == PARAMFLAG_FOUT:
                typ = self._argtypes_[idx]
                if getattr(typ, '_ffiargshape', None) not in ('P', 'z', 'Z'):
                    raise TypeError(
                        "'out' parameter %d must be a pointer type, not %s" %
                        (idx + 1, type(typ).__name__))
            elif _flag not in VALID_PARAMFLAGS:
                raise TypeError("paramflag value %d not supported" % flag)
        self._paramflags = paramflags

    paramflags = property(_getparamflags, _setparamflags)

    def _getrestype(self):
        return self._restype_

    def _setrestype(self, restype):
        self.__restype_set = True
        self._ptr = None
        if restype is int:
            from ctypes import c_int
            restype = c_int
        if not (isinstance(restype, _CDataMeta) or restype is None
                or callable(restype)):
            raise TypeError("restype must be a type, a callable, or None")
        self._restype_ = restype

    def _delrestype(self):
        self._ptr = None
        del self._restype_

    restype = property(_getrestype, _setrestype, _delrestype)

    def _geterrcheck(self):
        return getattr(self, '_errcheck_', None)

    def _seterrcheck(self, errcheck):
        if not callable(errcheck):
            raise TypeError("The errcheck attribute must be callable")
        self._errcheck_ = errcheck

    def _delerrcheck(self):
        try:
            del self._errcheck_
        except AttributeError:
            pass

    errcheck = property(_geterrcheck, _seterrcheck, _delerrcheck)

    def _ffishapes(self, args, restype):
        if args is None:
            args = []
        argtypes = [arg._ffiargshape for arg in args]
        if restype is not None:
            if not isinstance(restype, SimpleType):
                raise TypeError("invalid result type for callback function")
            restype = restype._ffiargshape
        else:
            restype = 'O'  # void
        return argtypes, restype

    def __init__(self, *args):
        self.name = None
        self._objects = {keepalive_key(0): self}
        self._needs_free = True

        # Empty function object -- this is needed for casts
        if not args:
            self._buffer = _rawffi.Array('P')(1)
            return

        argsl = list(args)
        argument = argsl.pop(0)

        # Direct construction from raw address
        if isinstance(argument, (int, long)) and not argsl:
            ffiargs, ffires = self._ffishapes(self._argtypes_, self._restype_)
            self._ptr = _rawffi.FuncPtr(argument, ffiargs, ffires,
                                        self._flags_)
            self._buffer = self._ptr.byptr()
            return

        # A callback into Python
        if callable(argument) and not argsl:
            self.callable = argument
            ffiargs, ffires = self._ffishapes(self._argtypes_, self._restype_)
            if self._restype_ is None:
                ffires = None
            self._ptr = _rawffi.CallbackPtr(
                self._wrap_callable(argument, self.argtypes), ffiargs, ffires,
                self._flags_)
            self._buffer = self._ptr.byptr()
            return

        # Function exported from a shared library
        if isinstance(argument, tuple) and len(argument) == 2:
            import ctypes
            self.name, dll = argument
            if isinstance(dll, str):
                self.dll = ctypes.CDLL(dll)
            else:
                self.dll = dll
            if argsl:
                self.paramflags = argsl.pop(0)
                if argsl:
                    raise TypeError("Unknown constructor %s" % (args, ))
            # We need to check dll anyway
            ptr = self._getfuncptr([], ctypes.c_int)
            self._buffer = ptr.byptr()
            return

        # A COM function call, by index
        if (sys.platform == 'win32' and isinstance(argument, (int, long))
                and argsl):
            ffiargs, ffires = self._ffishapes(self._argtypes_, self._restype_)
            self._com_index = argument + 0x1000
            self.name = argsl.pop(0)
            if argsl:
                self.paramflags = argsl.pop(0)
                if argsl:
                    self._com_iid = argsl.pop(0)
                    if argsl:
                        raise TypeError("Unknown constructor %s" % (args, ))
            return

        raise TypeError("Unknown constructor %s" % (args, ))

    def _wrap_callable(self, to_call, argtypes):
        def f(*args):
            if argtypes:
                args = [
                    argtype._CData_retval(argtype.from_address(arg)._buffer)
                    for argtype, arg in zip(argtypes, args)
                ]
            return to_call(*args)

        return f

    def __call__(self, *args, **kwargs):
        argtypes = self._argtypes_
        if self.callable is not None:
            if len(args) == len(argtypes):
                pass
            elif self._flags_ & _rawffi.FUNCFLAG_CDECL:
                if len(args) < len(argtypes):
                    plural = len(argtypes) > 1 and "s" or ""
                    raise TypeError(
                        "This function takes at least %d argument%s (%s given)"
                        % (len(argtypes), plural, len(args)))
                else:
                    # For cdecl functions, we allow more actual arguments
                    # than the length of the argtypes tuple.
                    args = args[:len(self._argtypes_)]
            else:
                plural = len(argtypes) > 1 and "s" or ""
                raise TypeError(
                    "This function takes %d argument%s (%s given)" %
                    (len(argtypes), plural, len(args)))

            # check that arguments are convertible
            ## XXX Not as long as ctypes.cast is a callback function with
            ## py_object arguments...
            ## self._convert_args(argtypes, args, {})

            try:
                res = self.callable(*args)
            except:
                exc_info = sys.exc_info()
                traceback.print_tb(exc_info[2], file=sys.stderr)
                print >> sys.stderr, "%s: %s" % (exc_info[0].__name__,
                                                 exc_info[1])
                return 0
            if self._restype_ is not None:
                return res
            return

        if argtypes is None:
            warnings.warn('C function without declared arguments called',
                          RuntimeWarning,
                          stacklevel=2)
            argtypes = []

        if not self.__restype_set:
            warnings.warn('C function without declared return type called',
                          RuntimeWarning,
                          stacklevel=2)

        if self._com_index:
            from ctypes import cast, c_void_p, POINTER
            if not args:
                raise ValueError(
                    "native COM method call without 'this' parameter")
            thisarg = cast(args[0], POINTER(POINTER(c_void_p))).contents
            argtypes = [c_void_p] + list(argtypes)
            args = list(args)
            args[0] = args[0].value
        else:
            thisarg = None

        args, outargs = self._convert_args(argtypes, args, kwargs)
        argtypes = [type(arg) for arg in args]

        restype = self._restype_
        funcptr = self._getfuncptr(argtypes, restype, thisarg)
        if self._flags_ & _rawffi.FUNCFLAG_USE_ERRNO:
            set_errno(_rawffi.get_errno())
        if self._flags_ & _rawffi.FUNCFLAG_USE_LASTERROR:
            set_last_error(_rawffi.get_last_error())
        try:
            resbuffer = funcptr(
                *[arg._get_buffer_for_param()._buffer for arg in args])
        finally:
            if self._flags_ & _rawffi.FUNCFLAG_USE_ERRNO:
                set_errno(_rawffi.get_errno())
            if self._flags_ & _rawffi.FUNCFLAG_USE_LASTERROR:
                set_last_error(_rawffi.get_last_error())

        result = None
        if self._com_index:
            if resbuffer[0] & 0x80000000:
                raise get_com_error(resbuffer[0], self._com_iid, args[0])
            else:
                result = int(resbuffer[0])
        elif restype is not None:
            checker = getattr(self.restype, '_check_retval_', None)
            if checker:
                val = restype(resbuffer[0])
                # the original ctypes seems to make the distinction between
                # classes defining a new type, and their subclasses
                if '_type_' in restype.__dict__:
                    val = val.value
                result = checker(val)
            elif not isinstance(restype, _CDataMeta):
                result = restype(resbuffer[0])
            else:
                result = restype._CData_retval(resbuffer)

        # The 'errcheck' protocol
        if self._errcheck_:
            v = self._errcheck_(result, self, args)
            # If the errcheck funtion failed, let it throw
            # If the errcheck function returned callargs unchanged,
            # continue normal processing.
            # If the errcheck function returned something else,
            # use that as result.
            if v is not args:
                result = v

        if not outargs:
            return result

        if len(outargs) == 1:
            return outargs[0]

        return tuple(outargs)

    def _getfuncptr(self, argtypes, restype, thisarg=None):
        if self._ptr is not None and argtypes is self._argtypes_:
            return self._ptr
        if restype is None or not isinstance(restype, _CDataMeta):
            import ctypes
            restype = ctypes.c_int
        argshapes = [arg._ffiargshape for arg in argtypes]
        resshape = restype._ffiargshape
        if self._buffer is not None:
            ptr = _rawffi.FuncPtr(self._buffer[0], argshapes, resshape,
                                  self._flags_)
            if argtypes is self._argtypes_:
                self._ptr = ptr
            return ptr

        if self._com_index:
            # extract the address from the object's virtual table
            if not thisarg:
                raise ValueError("COM method call without VTable")
            ptr = thisarg[self._com_index - 0x1000]
            return _rawffi.FuncPtr(ptr, argshapes, resshape, self._flags_)

        cdll = self.dll._handle
        try:
            return cdll.ptr(self.name, argshapes, resshape, self._flags_)
        except AttributeError:
            if self._flags_ & _rawffi.FUNCFLAG_CDECL:
                raise
            # Win64 has no stdcall calling conv, so it should also not have the
            # name mangling of it.
            if WIN64:
                raise
            # For stdcall, try mangled names:
            # funcname -> _funcname@<n>
            # where n is 0, 4, 8, 12, ..., 128
            for i in range(33):
                mangled_name = "_%s@%d" % (self.name, i * 4)
                try:
                    return cdll.ptr(mangled_name, argshapes, resshape,
                                    self._flags_)
                except AttributeError:
                    pass
            raise

    @staticmethod
    def _conv_param(argtype, arg):
        from ctypes import c_char_p, c_wchar_p, c_void_p, c_int
        if argtype is not None:
            arg = argtype.from_param(arg)
        if hasattr(arg, '_as_parameter_'):
            arg = arg._as_parameter_
        if isinstance(arg, _CData):
            # The usual case when argtype is defined
            cobj = arg
        elif isinstance(arg, str):
            cobj = c_char_p(arg)
        elif isinstance(arg, unicode):
            cobj = c_wchar_p(arg)
        elif arg is None:
            cobj = c_void_p()
        elif isinstance(arg, (int, long)):
            cobj = c_int(arg)
        else:
            raise TypeError("Don't know how to handle %s" % (arg, ))
        return cobj

    def _convert_args(self, argtypes, args, kwargs, marker=object()):
        callargs = []
        outargs = []
        total = len(args)
        paramflags = self._paramflags

        if self._com_index:
            inargs_idx = 1
        else:
            inargs_idx = 0

        if not paramflags and total < len(argtypes):
            raise TypeError("not enough arguments")

        for i, argtype in enumerate(argtypes):
            flag = 0
            name = None
            defval = marker
            if paramflags:
                paramflag = paramflags[i]
                paramlen = len(paramflag)
                name = None
                if paramlen == 1:
                    flag = paramflag[0]
                elif paramlen == 2:
                    flag, name = paramflag
                elif paramlen == 3:
                    flag, name, defval = paramflag
                flag = flag & PARAMFLAG_COMBINED
                if flag == PARAMFLAG_FIN | PARAMFLAG_FLCID:
                    val = defval
                    if val is marker:
                        val = 0
                    wrapped = self._conv_param(argtype, val)
                    callargs.append(wrapped)
                elif flag in (0, PARAMFLAG_FIN):
                    if inargs_idx < total:
                        val = args[inargs_idx]
                        inargs_idx += 1
                    elif kwargs and name in kwargs:
                        val = kwargs[name]
                        inargs_idx += 1
                    elif defval is not marker:
                        val = defval
                    elif name:
                        raise TypeError("required argument '%s' missing" %
                                        name)
                    else:
                        raise TypeError("not enough arguments")
                    wrapped = self._conv_param(argtype, val)
                    callargs.append(wrapped)
                elif flag == PARAMFLAG_FOUT:
                    if defval is not marker:
                        outargs.append(defval)
                        wrapped = self._conv_param(argtype, defval)
                    else:
                        import ctypes
                        val = argtype._type_()
                        outargs.append(val)
                        wrapped = ctypes.byref(val)
                    callargs.append(wrapped)
                else:
                    raise ValueError("paramflag %d not yet implemented" % flag)
            else:
                try:
                    wrapped = self._conv_param(argtype, args[i])
                except (UnicodeError, TypeError, ValueError), e:
                    raise ArgumentError(str(e))
                callargs.append(wrapped)
                inargs_idx += 1

        if len(callargs) < total:
            extra = args[len(callargs):]
            for i, arg in enumerate(extra):
                try:
                    wrapped = self._conv_param(None, arg)
                except (UnicodeError, TypeError, ValueError), e:
                    raise ArgumentError(str(e))
                callargs.append(wrapped)
Exemplo n.º 20
0
 def _set_address(self, address):
     if not self._buffer:
         self._buffer = _rawffi.Array('P')(1)
     self._buffer[0] = address
Exemplo n.º 21
0
class CFuncPtr(_CData, metaclass=CFuncPtrType):

    _argtypes_ = None
    _restype_ = None
    _errcheck_ = None
    _flags_ = 0
    _ffiargshape_ = 'P'
    _ffishape_ = 'P'
    _fficompositesize_ = None
    _ffiarray = _rawffi.Array('P')
    _needs_free = False
    callable = None
    _ptr = None
    _buffer = None
    _address = None
    # win32 COM properties
    _paramflags = None
    _com_index = None
    _com_iid = None
    _is_fastpath = False

    def _getargtypes(self):
        return self._argtypes_

    def _setargtypes(self, argtypes):
        self._ptr = None
        if argtypes is None:
            self._argtypes_ = ()
        else:
            for i, argtype in enumerate(argtypes):
                if not hasattr(argtype, 'from_param'):
                    raise TypeError(
                        "item %d in _argtypes_ has no from_param method" %
                        (i + 1, ))
            self._argtypes_ = list(argtypes)

    argtypes = property(_getargtypes, _setargtypes)

    def _getparamflags(self):
        return self._paramflags

    def _setparamflags(self, paramflags):
        if paramflags is None or not self._argtypes_:
            self._paramflags = None
            return
        if not isinstance(paramflags, tuple):
            raise TypeError("paramflags must be a tuple or None")
        if len(paramflags) != len(self._argtypes_):
            raise ValueError(
                "paramflags must have the same length as argtypes")
        for idx, paramflag in enumerate(paramflags):
            paramlen = len(paramflag)
            name = default = None
            if paramlen == 1:
                flag = paramflag[0]
            elif paramlen == 2:
                flag, name = paramflag
            elif paramlen == 3:
                flag, name, default = paramflag
            else:
                raise TypeError(
                    "paramflags must be a sequence of (int [,string [,value]]) "
                    "tuples")
            if not isinstance(flag, int):
                raise TypeError(
                    "paramflags must be a sequence of (int [,string [,value]]) "
                    "tuples")
            _flag = flag & PARAMFLAG_COMBINED
            if _flag == PARAMFLAG_FOUT:
                typ = self._argtypes_[idx]
                if getattr(typ, '_ffiargshape_', None) not in ('P', 'z', 'Z'):
                    raise TypeError(
                        "'out' parameter %d must be a pointer type, not %s" %
                        (idx + 1, type(typ).__name__))
            elif _flag not in VALID_PARAMFLAGS:
                raise TypeError("paramflag value %d not supported" % flag)
        self._paramflags = paramflags

    paramflags = property(_getparamflags, _setparamflags)

    def _getrestype(self):
        return self._restype_

    def _setrestype(self, restype):
        self._ptr = None
        if restype is int:
            from ctypes import c_int
            restype = c_int
        if not (isinstance(restype, _CDataMeta) or restype is None
                or callable(restype)):
            raise TypeError("restype must be a type, a callable, or None")
        self._restype_ = restype

    def _delrestype(self):
        self._ptr = None
        del self._restype_

    restype = property(_getrestype, _setrestype, _delrestype)

    def _geterrcheck(self):
        return getattr(self, '_errcheck_', None)

    def _seterrcheck(self, errcheck):
        if not callable(errcheck):
            raise TypeError("The errcheck attribute must be callable")
        self._errcheck_ = errcheck

    def _delerrcheck(self):
        try:
            del self._errcheck_
        except AttributeError:
            pass

    errcheck = property(_geterrcheck, _seterrcheck, _delerrcheck)

    def _ffishapes(self, args, restype):
        if args is None:
            args = []
        argtypes = [arg._ffiargshape_ for arg in args]
        if restype is not None:
            if not isinstance(restype, SimpleType):
                raise TypeError("invalid result type for callback function")
            restype = restype._ffiargshape_
        else:
            restype = 'O'  # void
        return argtypes, restype

    def _set_address(self, address):
        if not self._buffer:
            self._buffer = _rawffi.Array('P')(1)
        self._buffer[0] = address

    def _get_address(self):
        return self._buffer[0]

    def __init__(self, *args):
        self.name = None
        self._objects = {keepalive_key(0): self}
        self._needs_free = True

        # Empty function object -- this is needed for casts
        if not args:
            self._set_address(0)
            return

        argsl = list(args)
        argument = argsl.pop(0)

        # Direct construction from raw address
        if isinstance(argument, int) and not argsl:
            self._set_address(argument)
            restype = self._restype_
            if restype is None:
                import ctypes
                restype = ctypes.c_int
            if self._argtypes_ is None:
                self._argtypes_ = []
            self._ptr = self._getfuncptr_fromaddress(self._argtypes_, restype)
            return

        # A callback into python
        if callable(argument) and not argsl:
            self.callable = argument
            ffiargs, ffires = self._ffishapes(self._argtypes_, self._restype_)
            if self._restype_ is None:
                ffires = None
            self._ptr = _rawffi.CallbackPtr(
                self._wrap_callable(argument, self.argtypes), ffiargs, ffires,
                self._flags_)
            self._buffer = self._ptr.byptr()
            return

        # Function exported from a shared library
        if isinstance(argument, tuple) and len(argument) == 2:
            import ctypes
            self.name, dll = argument
            if isinstance(dll, str):
                self.dll = ctypes.CDLL(self.dll)
            else:
                self.dll = dll
            if argsl:
                self.paramflags = argsl.pop(0)
                if argsl:
                    raise TypeError("Unknown constructor %s" % (args, ))
            # We need to check dll anyway
            ptr = self._getfuncptr([], ctypes.c_int)
            self._set_address(ptr.getaddr())
            return

        # A COM function call, by index
        if (sys.platform == 'win32' and isinstance(argument, int) and argsl):
            ffiargs, ffires = self._ffishapes(self._argtypes_, self._restype_)
            self._com_index = argument + 0x1000
            self.name = argsl.pop(0)
            if argsl:
                self.paramflags = argsl.pop(0)
                if argsl:
                    self._com_iid = argsl.pop(0)
                    if argsl:
                        raise TypeError("Unknown constructor %s" % (args, ))
            return

        raise TypeError("Unknown constructor %s" % (args, ))

    _init_no_arg_ = __init__

    def _wrap_callable(self, to_call, argtypes):
        def f(*args):
            if argtypes:
                args = [
                    argtype._CData_retval(argtype.from_address(arg)._buffer)
                    for argtype, arg in zip(argtypes, args)
                ]
            try:
                return to_call(*args)
            except SystemExit as e:
                handle_system_exit(e)
                raise

        return f

    def __call__(self, *args, **kwargs):
        argtypes = self._argtypes_
        if self.callable is not None:
            if len(args) == len(argtypes):
                pass
            elif self._flags_ & _rawffi.FUNCFLAG_CDECL:
                if len(args) < len(argtypes):
                    plural = len(argtypes) > 1 and "s" or ""
                    raise TypeError(
                        "This function takes at least %d argument%s (%s given)"
                        % (len(argtypes), plural, len(args)))
                else:
                    # For cdecl functions, we allow more actual arguments
                    # than the length of the argtypes tuple.
                    args = args[:len(self._argtypes_)]
            else:
                plural = len(self._argtypes_) > 1 and "s" or ""
                raise TypeError(
                    "This function takes %d argument%s (%s given)" %
                    (len(self._argtypes_), plural, len(args)))

            try:
                newargs = self._convert_args_for_callback(argtypes, args)
            except (UnicodeError, TypeError, ValueError) as e:
                raise ArgumentError(str(e))
            try:
                try:
                    res = self.callable(*newargs)
                except SystemExit as e:
                    handle_system_exit(e)
                    raise
            except:
                exc_info = sys.exc_info()
                traceback.print_tb(exc_info[2], file=sys.stderr)
                print("%s: %s" % (exc_info[0].__name__, exc_info[1]),
                      file=sys.stderr)
                return 0
            if self._restype_ is not None:
                return res
            return

        if argtypes is None:
            # XXX this warning was originally meaning "it's going to be
            # really slow".  Now we don't worry that much about slowness
            # of ctypes, and it's strange to get warnings for perfectly-
            # legal code.
            # warnings.warn('C function without declared arguments called',
            #              RuntimeWarning, stacklevel=2)
            argtypes = []

        if self._com_index:
            from ctypes import cast, c_void_p, POINTER
            if not args:
                raise ValueError(
                    "native COM method call without 'this' parameter")
            thisvalue = args[0]
            thisarg = cast(thisvalue, POINTER(POINTER(c_void_p)))
            keepalives, newargs, argtypes, outargs, errcheckargs = (
                self._convert_args(argtypes, args[1:], kwargs))
            newargs.insert(0, thisarg)
            argtypes.insert(0, c_void_p)
        else:
            thisarg = None
            keepalives, newargs, argtypes, outargs, errcheckargs = (
                self._convert_args(argtypes, args, kwargs))

        funcptr = self._getfuncptr(argtypes, self._restype_, thisarg)
        result = self._call_funcptr(funcptr, *newargs)
        result, forced = self._do_errcheck(result, errcheckargs)

        if not outargs or forced:
            return result

        from ctypes import c_void_p
        simple_cdata = type(c_void_p()).__bases__[0]
        outargs = [
            x.value if type(x).__bases__[0] is simple_cdata else x
            for x in outargs
        ]

        if len(outargs) == 1:
            return outargs[0]
        return tuple(outargs)

    def _call_funcptr(self, funcptr, *newargs):
        if self._flags_ & _rawffi.FUNCFLAG_USE_ERRNO:
            tmp = _rawffi.get_errno()
            _rawffi.set_errno(get_errno())
            set_errno(tmp)
        if self._flags_ & _rawffi.FUNCFLAG_USE_LASTERROR:
            tmp = _rawffi.get_last_error()
            _rawffi.set_last_error(get_last_error())
            set_last_error(tmp)
        try:
            result = funcptr(*newargs)
        finally:
            if self._flags_ & _rawffi.FUNCFLAG_USE_ERRNO:
                tmp = _rawffi.get_errno()
                _rawffi.set_errno(get_errno())
                set_errno(tmp)
            if self._flags_ & _rawffi.FUNCFLAG_USE_LASTERROR:
                tmp = _rawffi.get_last_error()
                _rawffi.set_last_error(get_last_error())
                set_last_error(tmp)
        #
        try:
            return self._build_result(self._restype_, result)
        finally:
            funcptr.free_temp_buffers()

    def _do_errcheck(self, result, args):
        # The 'errcheck' protocol
        if self._errcheck_:
            v = self._errcheck_(result, self, tuple(args))
            # If the errcheck funtion failed, let it throw
            # If the errcheck function returned newargs unchanged,
            # continue normal processing.
            # If the errcheck function returned something else,
            # use that as result.
            if v is not args:
                return v, True
        return result, False

    def _getfuncptr_fromaddress(self, argtypes, restype):
        address = self._get_address()
        ffiargs = [argtype.get_ffi_argtype() for argtype in argtypes]
        ffires = restype.get_ffi_argtype()
        return _ffi.FuncPtr.fromaddr(address, '', ffiargs, ffires,
                                     self._flags_)

    def _getfuncptr(self, argtypes, restype, thisarg=None):
        if self._ptr is not None and (argtypes is self._argtypes_
                                      or argtypes == self._argtypes_):
            return self._ptr
        if restype is None or not isinstance(restype, _CDataMeta):
            import ctypes
            restype = ctypes.c_int
        if self._buffer is not None:
            ptr = self._getfuncptr_fromaddress(argtypes, restype)
            if argtypes == self._argtypes_:
                self._ptr = ptr
            return ptr

        if self._com_index:
            # extract the address from the object's virtual table
            if not thisarg:
                raise ValueError("COM method call without VTable")
            ptr = thisarg[0][self._com_index - 0x1000]
            ffiargs = [argtype.get_ffi_argtype() for argtype in argtypes]
            ffires = restype.get_ffi_argtype()
            return _ffi.FuncPtr.fromaddr(ptr, '', ffiargs, ffires,
                                         self._flags_)

        cdll = self.dll.__pypy_dll__
        try:
            ffi_argtypes = [argtype.get_ffi_argtype() for argtype in argtypes]
            ffi_restype = restype.get_ffi_argtype()
            self._ptr = cdll.getfunc(self.name, ffi_argtypes, ffi_restype)
            return self._ptr
        except AttributeError:
            if self._flags_ & _rawffi.FUNCFLAG_CDECL:
                raise

            # Win64 has no stdcall calling conv, so it should also not have the
            # name mangling of it.
            if WIN64:
                raise
            # For stdcall, try mangled names:
            # funcname -> _funcname@<n>
            # where n is 0, 4, 8, 12, ..., 128
            for i in range(33):
                mangled_name = "_%s@%d" % (self.name, i * 4)
                try:
                    return cdll.getfunc(
                        mangled_name,
                        ffi_argtypes,
                        ffi_restype,
                        # XXX self._flags_
                    )
                except AttributeError:
                    pass
            raise

    @classmethod
    def _conv_param(cls, argtype, arg):
        if argtype is not None:
            arg = argtype.from_param(arg)
        if hasattr(arg, '_as_parameter_'):
            arg = arg._as_parameter_
        if isinstance(arg, _CData):
            return arg, arg._to_ffi_param(), type(arg)
        #
        # non-usual case: we do the import here to save a lot of code in the
        # jit trace of the normal case
        from ctypes import c_char_p, c_wchar_p, c_void_p, c_int
        #
        if isinstance(arg, bytes):
            cobj = c_char_p(arg)
        elif isinstance(arg, str):
            cobj = c_wchar_p(arg)
        elif arg is None:
            cobj = c_void_p()
        elif isinstance(arg, int):
            cobj = c_int(arg)
        else:
            raise TypeError("Don't know how to handle %s" % (arg, ))

        return cobj, cobj._to_ffi_param(), type(cobj)

    def _convert_args_for_callback(self, argtypes, args):
        from _ctypes.structure import StructOrUnion
        #
        assert len(argtypes) == len(args)
        newargs = []
        for argtype, arg in zip(argtypes, args):
            param = argtype.from_param(arg)
            _type_ = getattr(argtype, '_type_', None)
            if _type_ == 'P':  # special-case for c_void_p
                param = param._get_buffer_value()
            elif self._is_primitive(argtype):
                param = param.value
            elif isinstance(param, StructOrUnion):  # not a *pointer* to struct
                newparam = StructOrUnion.__new__(type(param))
                param._copy_to(newparam._buffer.buffer)
                param = newparam
            newargs.append(param)
        return newargs

    def _convert_args(self, argtypes, args, kwargs, marker=object()):
        newargs = []
        outargs = []
        keepalives = []
        newargtypes = []
        total = len(args)
        paramflags = self._paramflags

        if not paramflags and total < len(argtypes):
            raise TypeError("not enough arguments")

        if paramflags:
            errcheckargs = []
            inargs_idx = 0
            for i, argtype in enumerate(argtypes):
                flag = 0
                defval = marker
                paramflag = paramflags[i]
                paramlen = len(paramflag)
                name = None
                if paramlen == 1:
                    flag = paramflag[0]
                elif paramlen == 2:
                    flag, name = paramflag
                elif paramlen == 3:
                    flag, name, defval = paramflag
                flag = flag & PARAMFLAG_COMBINED
                if flag == PARAMFLAG_FIN | PARAMFLAG_FLCID:
                    val = defval
                    if val is marker:
                        val = 0
                    errcheckargs.append(val)
                    keepalive, newarg, newargtype = self._conv_param(
                        argtype, val)
                    keepalives.append(keepalive)
                    newargs.append(newarg)
                    newargtypes.append(newargtype)
                elif flag in (0, PARAMFLAG_FIN):
                    if inargs_idx < total:
                        val = args[inargs_idx]
                        inargs_idx += 1
                    elif kwargs and name in kwargs:
                        val = kwargs[name]
                        inargs_idx += 1
                    elif defval is not marker:
                        val = defval
                    elif name:
                        raise TypeError("required argument '%s' missing" %
                                        name)
                    else:
                        raise TypeError("not enough arguments")
                    errcheckargs.append(val)
                    keepalive, newarg, newargtype = self._conv_param(
                        argtype, val)
                    keepalives.append(keepalive)
                    newargs.append(newarg)
                    newargtypes.append(newargtype)
                elif flag == PARAMFLAG_FOUT:
                    if defval is not marker:
                        val = defval
                        keepalive, newarg, newargtype = self._conv_param(
                            argtype, defval)
                    else:
                        import ctypes
                        val = argtype._type_._newowninstance_()
                        keepalive = None
                        newarg = ctypes.byref(val)
                        newargtype = type(newarg)
                    errcheckargs.append(val)
                    outargs.append(val)
                    keepalives.append(keepalive)
                    newargs.append(newarg)
                    newargtypes.append(newargtype)
                else:
                    raise ValueError("paramflag %d not yet implemented" % flag)
        else:
            errcheckargs = args
            for i, argtype in enumerate(argtypes):
                try:
                    keepalive, newarg, newargtype = self._conv_param(
                        argtype, args[i])
                except (UnicodeError, TypeError, ValueError) as e:
                    raise ArgumentError(str(e))
                keepalives.append(keepalive)
                newargs.append(newarg)
                newargtypes.append(newargtype)

        if len(newargs) < len(args):
            extra = args[len(newargs):]
            for i, arg in enumerate(extra):
                try:
                    keepalive, newarg, newargtype = self._conv_param(None, arg)
                except (UnicodeError, TypeError, ValueError) as e:
                    raise ArgumentError(str(e))
                keepalives.append(keepalive)
                newargs.append(newarg)
                newargtypes.append(newargtype)
        return keepalives, newargs, newargtypes, outargs, errcheckargs

    @staticmethod
    def _is_primitive(argtype):
        return argtype.__bases__[0] is _SimpleCData

    def _wrap_result(self, restype, result):
        """
        Convert from low-level repr of the result to the high-level python
        one.
        """
        # hack for performance: if restype is a "simple" primitive type, don't
        # allocate the buffer because it's going to be thrown away immediately
        if (self._is_primitive(restype) and restype._type_ != '?'
                and not restype._is_pointer_like()):
            return result
        #
        shape = restype._ffishape_
        if is_struct_shape(shape):
            buf = result
        else:
            buf = _rawffi.Array(shape)(1, autofree=True)
            buf[0] = result
        retval = restype._CData_retval(buf)
        return retval

    def _build_result(self, restype, result):
        """Build the function result:
           If there is no OUT parameter, return the actual function result
           If there is one OUT parameter, return it
           If there are many OUT parameters, return a tuple"""

        # XXX: note for the future: the function used to take a "resbuffer",
        # i.e. an array of ints. Now it takes a result, which is already a
        # python object. All places that do "resbuffer[0]" should check that
        # result is actually an int and just use it.

        retval = None

        if restype is not None:
            checker = getattr(self.restype, '_check_retval_', None)
            if checker:
                val = restype(result)
                # the original ctypes seems to make the distinction between
                # classes defining a new type, and their subclasses
                if '_type_' in restype.__dict__:
                    val = val.value
                # XXX Raise a COMError when restype is HRESULT and
                # checker(val) fails.  How to check for restype == HRESULT?
                if self._com_index:
                    if result & 0x80000000:
                        raise get_com_error(result, None, None)
                else:
                    retval = checker(val)
            elif not isinstance(restype, _CDataMeta):
                retval = restype(result)
            else:
                retval = self._wrap_result(restype, result)

        return retval

    def __bool__(self):
        return self._com_index is not None or bool(self._buffer[0])

    def __del__(self):
        if self._needs_free:
            # XXX we need to find a bad guy here
            if self._buffer is None:
                return
            self._buffer.free()
            self._buffer = None
            if isinstance(self._ptr, _rawffi.CallbackPtr):
                self._ptr.free()
                self._ptr = None
            self._needs_free = False
Exemplo n.º 22
0
 def test_negative_pointers(self):
     import _rawffi
     A = _rawffi.Array('P')
     a = A(1)
     a[0] = -1234
     a.free()
Exemplo n.º 23
0
 def test_overflow_error(self):
     import _rawffi
     A = _rawffi.Array('d')
     arg1 = A(1)
     raises(OverflowError, "arg1[0] = 10**900")
     arg1.free()
Exemplo n.º 24
0
    def test_truncate(self):
        import _rawffi, struct
        a = _rawffi.Array('b')(1)
        a[0] = -5
        assert a[0] == -5
        a[0] = 123L
        assert a[0] == 123
        a[0] = 0x97817182ab128111111111111171817d042
        assert a[0] == 0x42
        a[0] = 255
        assert a[0] == -1
        a[0] = -2
        assert a[0] == -2
        a[0] = -255
        assert a[0] == 1
        a.free()

        a = _rawffi.Array('B')(1)
        a[0] = 123L
        assert a[0] == 123
        a[0] = 0x18329b1718b97d89b7198db817d042
        assert a[0] == 0x42
        a[0] = 255
        assert a[0] == 255
        a[0] = -2
        assert a[0] == 254
        a[0] = -255
        assert a[0] == 1
        a.free()

        a = _rawffi.Array('h')(1)
        a[0] = 123L
        assert a[0] == 123
        a[0] = 0x9112cbc91bd91db19aaaaaaaaaaaaaa8170d42
        assert a[0] == 0x0d42
        a[0] = 65535
        assert a[0] == -1
        a[0] = -2
        assert a[0] == -2
        a[0] = -65535
        assert a[0] == 1
        a.free()

        a = _rawffi.Array('H')(1)
        a[0] = 123L
        assert a[0] == 123
        a[0] = 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeee817d042
        assert a[0] == 0xd042
        a[0] = -2
        assert a[0] == 65534
        a.free()

        maxptr = (256**struct.calcsize("P")) - 1
        a = _rawffi.Array('P')(1)
        a[0] = 123L
        assert a[0] == 123
        a[0] = 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeee817d042
        assert a[0] == 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeee817d042 & maxptr
        a[0] = -2
        assert a[0] == maxptr - 1
        a.free()
Exemplo n.º 25
0
    def __new__(self, name, cls, typedict):
        res = type.__new__(self, name, cls, typedict)

        if cls == (_CData, ):  # this is the Array class defined below
            res._ffiarray = None
            return res
        if not hasattr(res, '_length_') or not isinstance(
                res._length_, (int, long)):
            raise AttributeError("class must define a '_length_' attribute, "
                                 "which must be a positive integer")
        ffiarray = res._ffiarray = _rawffi.Array(res._type_._ffishape_)
        subletter = getattr(res._type_, '_type_', None)
        if subletter == 'c':

            def getvalue(self):
                return _rawffi.charp2string(self._buffer.buffer, self._length_)

            def setvalue(self, val):
                # we don't want to have buffers here
                if len(val) > self._length_:
                    raise ValueError("%r too long" % (val, ))
                if isinstance(val, str):
                    _rawffi.rawstring2charp(self._buffer.buffer, val)
                else:
                    for i in range(len(val)):
                        self[i] = val[i]
                if len(val) < self._length_:
                    self._buffer[len(val)] = b'\x00'

            res.value = property(getvalue, setvalue)

            def getraw(self):
                return _rawffi.charp2rawstring(self._buffer.buffer,
                                               self._length_)

            def setraw(self, buffer):
                if len(buffer) > self._length_:
                    raise ValueError("%r too long" % (buffer, ))
                _rawffi.rawstring2charp(self._buffer.buffer, buffer)

            res.raw = property(getraw, setraw)
        elif subletter == 'u':

            def getvalue(self):
                return _rawffi.wcharp2unicode(self._buffer.buffer,
                                              self._length_)

            def setvalue(self, val):
                # we don't want to have buffers here
                if len(val) > self._length_:
                    raise ValueError("%r too long" % (val, ))
                if isinstance(val, unicode):
                    target = self._buffer
                else:
                    target = self
                for i in range(len(val)):
                    target[i] = val[i]
                if len(val) < self._length_:
                    target[len(val)] = u'\x00'

            res.value = property(getvalue, setvalue)

        res._ffishape_ = (ffiarray, res._length_)
        res._fficompositesize_ = res._sizeofinstances()
        return res
Exemplo n.º 26
0
class CFuncPtr(_CData):
    __metaclass__ = CFuncPtrType

    _argtypes_ = None
    _restype_ = None
    _errcheck_ = None
    _flags_ = 0
    _ffiargshape = 'P'
    _ffishape = 'P'
    _fficompositesize = None
    _ffiarray = _rawffi.Array('P')
    _needs_free = False
    callable = None
    _ptr = None
    _buffer = None
    _address = None
    # win32 COM properties
    _paramflags = None
    _com_index = None
    _com_iid = None
    _is_fastpath = False

    def _getargtypes(self):
        return self._argtypes_

    def _setargtypes(self, argtypes):
        self._ptr = None
        if argtypes is None:
            self._argtypes_ = ()
        else:
            for i, argtype in enumerate(argtypes):
                if not hasattr(argtype, 'from_param'):
                    raise TypeError(
                        "item %d in _argtypes_ has no from_param method" %
                        (i + 1, ))
            self._argtypes_ = list(argtypes)
            self._check_argtypes_for_fastpath()

    argtypes = property(_getargtypes, _setargtypes)

    def _check_argtypes_for_fastpath(self):
        if all(
            [hasattr(argtype, '_ffiargshape') for argtype in self._argtypes_]):
            fastpath_cls = make_fastpath_subclass(self.__class__)
            fastpath_cls.enable_fastpath_maybe(self)

    def _getparamflags(self):
        return self._paramflags

    def _setparamflags(self, paramflags):
        if paramflags is None or not self._argtypes_:
            self._paramflags = None
            return
        if not isinstance(paramflags, tuple):
            raise TypeError("paramflags must be a tuple or None")
        if len(paramflags) != len(self._argtypes_):
            raise ValueError(
                "paramflags must have the same length as argtypes")
        for idx, paramflag in enumerate(paramflags):
            paramlen = len(paramflag)
            name = default = None
            if paramlen == 1:
                flag = paramflag[0]
            elif paramlen == 2:
                flag, name = paramflag
            elif paramlen == 3:
                flag, name, default = paramflag
            else:
                raise TypeError(
                    "paramflags must be a sequence of (int [,string [,value]]) "
                    "tuples")
            if not isinstance(flag, int):
                raise TypeError(
                    "paramflags must be a sequence of (int [,string [,value]]) "
                    "tuples")
            _flag = flag & PARAMFLAG_COMBINED
            if _flag == PARAMFLAG_FOUT:
                typ = self._argtypes_[idx]
                if getattr(typ, '_ffiargshape', None) not in ('P', 'z', 'Z'):
                    raise TypeError(
                        "'out' parameter %d must be a pointer type, not %s" %
                        (idx + 1, type(typ).__name__))
            elif _flag not in VALID_PARAMFLAGS:
                raise TypeError("paramflag value %d not supported" % flag)
        self._paramflags = paramflags

    paramflags = property(_getparamflags, _setparamflags)

    def _getrestype(self):
        return self._restype_

    def _setrestype(self, restype):
        self._ptr = None
        if restype is int:
            from ctypes import c_int
            restype = c_int
        if not (isinstance(restype, _CDataMeta) or restype is None
                or callable(restype)):
            raise TypeError("restype must be a type, a callable, or None")
        self._restype_ = restype

    def _delrestype(self):
        self._ptr = None
        del self._restype_

    restype = property(_getrestype, _setrestype, _delrestype)

    def _geterrcheck(self):
        return getattr(self, '_errcheck_', None)

    def _seterrcheck(self, errcheck):
        if not callable(errcheck):
            raise TypeError("The errcheck attribute must be callable")
        self._errcheck_ = errcheck

    def _delerrcheck(self):
        try:
            del self._errcheck_
        except AttributeError:
            pass

    errcheck = property(_geterrcheck, _seterrcheck, _delerrcheck)

    def _ffishapes(self, args, restype):
        if args is None:
            args = []
        argtypes = [arg._ffiargshape for arg in args]
        if restype is not None:
            if not isinstance(restype, SimpleType):
                raise TypeError("invalid result type for callback function")
            restype = restype._ffiargshape
        else:
            restype = 'O'  # void
        return argtypes, restype

    def _set_address(self, address):
        if not self._buffer:
            self._buffer = _rawffi.Array('P')(1)
        self._buffer[0] = address

    def _get_address(self):
        return self._buffer[0]

    def __init__(self, *args):
        self.name = None
        self._objects = {keepalive_key(0): self}
        self._needs_free = True

        # Empty function object -- this is needed for casts
        if not args:
            self._set_address(0)
            return

        argsl = list(args)
        argument = argsl.pop(0)

        # Direct construction from raw address
        if isinstance(argument, (int, long)) and not argsl:
            self._set_address(argument)
            restype = self._restype_
            if restype is None:
                import ctypes
                restype = ctypes.c_int
            self._ptr = self._getfuncptr_fromaddress(self._argtypes_, restype)
            self._check_argtypes_for_fastpath()
            return

        # A callback into python
        if callable(argument) and not argsl:
            self.callable = argument
            ffiargs, ffires = self._ffishapes(self._argtypes_, self._restype_)
            if self._restype_ is None:
                ffires = None
            self._ptr = _rawffi.CallbackPtr(
                self._wrap_callable(argument, self.argtypes), ffiargs, ffires,
                self._flags_)
            self._buffer = self._ptr.byptr()
            return

        # Function exported from a shared library
        if isinstance(argument, tuple) and len(argument) == 2:
            import ctypes
            self.name, dll = argument
            if isinstance(dll, str):
                self.dll = ctypes.CDLL(self.dll)
            else:
                self.dll = dll
            if argsl:
                self.paramflags = argsl.pop(0)
                if argsl:
                    raise TypeError("Unknown constructor %s" % (args, ))
            # We need to check dll anyway
            ptr = self._getfuncptr([], ctypes.c_int)
            self._set_address(ptr.getaddr())
            return

        # A COM function call, by index
        if (sys.platform == 'win32' and isinstance(argument, (int, long))
                and argsl):
            ffiargs, ffires = self._ffishapes(self._argtypes_, self._restype_)
            self._com_index = argument + 0x1000
            self.name = argsl.pop(0)
            if argsl:
                self.paramflags = argsl.pop(0)
                if argsl:
                    self._com_iid = argsl.pop(0)
                    if argsl:
                        raise TypeError("Unknown constructor %s" % (args, ))
            return

        raise TypeError("Unknown constructor %s" % (args, ))

    def _wrap_callable(self, to_call, argtypes):
        def f(*args):
            if argtypes:
                args = [
                    argtype._CData_retval(argtype.from_address(arg)._buffer)
                    for argtype, arg in zip(argtypes, args)
                ]
            return to_call(*args)

        return f

    def __call__(self, *args, **kwargs):
        argtypes = self._argtypes_
        if self.callable is not None:
            if len(args) == len(argtypes):
                pass
            elif self._flags_ & _rawffi.FUNCFLAG_CDECL:
                if len(args) < len(argtypes):
                    plural = len(argtypes) > 1 and "s" or ""
                    raise TypeError(
                        "This function takes at least %d argument%s (%s given)"
                        % (len(argtypes), plural, len(args)))
                else:
                    # For cdecl functions, we allow more actual arguments
                    # than the length of the argtypes tuple.
                    args = args[:len(self._argtypes_)]
            else:
                plural = len(self._argtypes_) > 1 and "s" or ""
                raise TypeError(
                    "This function takes %d argument%s (%s given)" %
                    (len(self._argtypes_), plural, len(args)))

            try:
                newargs = self._convert_args_for_callback(argtypes, args)
            except (UnicodeError, TypeError, ValueError), e:
                raise ArgumentError(str(e))
            try:
                res = self.callable(*newargs)
            except:
                exc_info = sys.exc_info()
                traceback.print_tb(exc_info[2], file=sys.stderr)
                print >> sys.stderr, "%s: %s" % (exc_info[0].__name__,
                                                 exc_info[1])
                return 0
            if self._restype_ is not None:
                return res
            return

        if argtypes is None:
            warnings.warn('C function without declared arguments called',
                          RuntimeWarning,
                          stacklevel=2)
            argtypes = []

        if self._com_index:
            from ctypes import cast, c_void_p, POINTER
            if not args:
                raise ValueError(
                    "native COM method call without 'this' parameter")
            thisarg = cast(args[0], POINTER(POINTER(c_void_p)))
            keepalives, newargs, argtypes, outargs = self._convert_args(
                argtypes, args[1:], kwargs)
            newargs.insert(0, args[0].value)
            argtypes.insert(0, c_void_p)
        else:
            thisarg = None
            keepalives, newargs, argtypes, outargs = self._convert_args(
                argtypes, args, kwargs)

        funcptr = self._getfuncptr(argtypes, self._restype_, thisarg)
        result = self._call_funcptr(funcptr, *newargs)
        result = self._do_errcheck(result, args)

        if not outargs:
            return result

        simple_cdata = type(c_void_p()).__bases__[0]
        outargs = [
            x.value if type(x).__bases__[0] is simple_cdata else x
            for x in outargs
        ]

        if len(outargs) == 1:
            return outargs[0]
        return tuple(outargs)
Exemplo n.º 27
0
 def test_long_with_fromaddress(self):
     import _rawffi
     addr = -1
     raises(ValueError, _rawffi.Array('u').fromaddress, addr, 100)
Exemplo n.º 28
0
        # the STDCALL calling convention may detect some errors
        import _rawffi
        lib = _rawffi.CDLL('kernel32')

        f = lib.ptr('SetLastError', [], 'i')
        try:
            f()
        except ValueError, e:
            assert "Procedure called with not enough arguments" in e.message
        else:
            assert 0, "Did not raise"

        f = lib.ptr('GetLastError', ['i'],
                    None,
                    flags=_rawffi.FUNCFLAG_STDCALL)
        arg = _rawffi.Array('i')(1)
        arg[0] = 1
        try:
            f(arg)
        except ValueError, e:
            assert "Procedure called with too many arguments" in e.message
        else:
            assert 0, "Did not raise"
        arg.free()

    def test_struct_byvalue(self):
        import _rawffi, sys
        X_Y = _rawffi.Structure([('x', 'l'), ('y', 'l')])
        x_y = X_Y()
        lib = _rawffi.CDLL(self.lib_name)
        print >> sys.stderr, "getting..."
Exemplo n.º 29
0
 def getprimitive(typecode, name):
     addr = lib.getaddressindll(name)
     return _rawffi.Array(typecode).fromaddress(addr, 1)
Exemplo n.º 30
0
    def __new__(self, name, bases, dct):
        try:
            tp = dct['_type_']
        except KeyError:
            for base in bases:
                if hasattr(base, '_type_'):
                    tp = base._type_
                    break
            else:
                raise AttributeError("cannot find _type_ attribute")
        if (not isinstance(tp, str) or not len(tp) == 1
                or tp not in SIMPLE_TYPE_CHARS):
            raise ValueError('%s is not a type character' % (tp))
        default = TP_TO_DEFAULT[tp]
        ffiarray = _rawffi.Array(tp)
        result = type.__new__(self, name, bases, dct)
        result._ffiargshape = tp
        result._ffishape = tp
        result._fficompositesize = None
        result._ffiarray = ffiarray
        if tp == 'z':
            # c_char_p
            def _getvalue(self):
                addr = self._buffer[0]
                if addr == 0:
                    return None
                else:
                    return _rawffi.charp2string(addr)

            def _setvalue(self, value):
                if isinstance(value, basestring):
                    if isinstance(value, unicode):
                        value = value.encode(ConvMode.encoding,
                                             ConvMode.errors)
                    #self._objects = value
                    array = _rawffi.Array('c')(len(value) + 1, value)
                    self._objects = CArgObject(value, array)
                    value = array.buffer
                elif value is None:
                    value = 0
                self._buffer[0] = value

            result.value = property(_getvalue, _setvalue)
            result._ffiargtype = _ffi.types.Pointer(_ffi.types.char)

        elif tp == 'Z':
            # c_wchar_p
            def _getvalue(self):
                addr = self._buffer[0]
                if addr == 0:
                    return None
                else:
                    return _rawffi.wcharp2unicode(addr)

            def _setvalue(self, value):
                if isinstance(value, basestring):
                    if isinstance(value, str):
                        value = value.decode(ConvMode.encoding,
                                             ConvMode.errors)
                    #self._objects = value
                    array = _rawffi.Array('u')(len(value) + 1, value)
                    self._objects = CArgObject(value, array)
                    value = array.buffer
                elif value is None:
                    value = 0
                self._buffer[0] = value

            result.value = property(_getvalue, _setvalue)
            result._ffiargtype = _ffi.types.Pointer(_ffi.types.unichar)

        elif tp == 'P':
            # c_void_p

            def _getvalue(self):
                addr = self._buffer[0]
                if addr == 0:
                    return None
                return addr

            def _setvalue(self, value):
                if isinstance(value, str):
                    array = _rawffi.Array('c')(len(value) + 1, value)
                    self._objects = CArgObject(value, array)
                    value = array.buffer
                elif value is None:
                    value = 0
                self._buffer[0] = value

            result.value = property(_getvalue, _setvalue)

        elif tp == 'u':

            def _setvalue(self, val):
                if isinstance(val, str):
                    val = val.decode(ConvMode.encoding, ConvMode.errors)
                # possible if we use 'ignore'
                if val:
                    self._buffer[0] = val

            def _getvalue(self):
                return self._buffer[0]

            result.value = property(_getvalue, _setvalue)

        elif tp == 'c':

            def _setvalue(self, val):
                if isinstance(val, unicode):
                    val = val.encode(ConvMode.encoding, ConvMode.errors)
                if val:
                    self._buffer[0] = val

            def _getvalue(self):
                return self._buffer[0]

            result.value = property(_getvalue, _setvalue)

        elif tp == 'O':

            def _setvalue(self, val):
                num = pyobj_container.add(val)
                self._buffer[0] = num

            def _getvalue(self):
                return pyobj_container.get(self._buffer[0])

            result.value = property(_getvalue, _setvalue)

        elif tp == 'X':
            from ctypes import WinDLL
            # Use WinDLL("oleaut32") instead of windll.oleaut32
            # because the latter is a shared (cached) object; and
            # other code may set their own restypes. We need out own
            # restype here.
            oleaut32 = WinDLL("oleaut32")
            SysAllocStringLen = oleaut32.SysAllocStringLen
            SysStringLen = oleaut32.SysStringLen
            SysFreeString = oleaut32.SysFreeString

            def _getvalue(self):
                addr = self._buffer[0]
                if addr == 0:
                    return None
                else:
                    size = SysStringLen(addr)
                    return _rawffi.wcharp2rawunicode(addr, size)

            def _setvalue(self, value):
                if isinstance(value, basestring):
                    if isinstance(value, str):
                        value = value.decode(ConvMode.encoding,
                                             ConvMode.errors)
                    array = _rawffi.Array('u')(len(value) + 1, value)
                    value = SysAllocStringLen(array.buffer, len(value))
                elif value is None:
                    value = 0
                if self._buffer[0]:
                    SysFreeString(self._buffer[0])
                self._buffer[0] = value

            result.value = property(_getvalue, _setvalue)

        elif tp == 'v':  # VARIANT_BOOL type

            def _getvalue(self):
                return bool(self._buffer[0])

            def _setvalue(self, value):
                if value:
                    self._buffer[0] = -1  # VARIANT_TRUE
                else:
                    self._buffer[0] = 0  # VARIANT_FALSE

            result.value = property(_getvalue, _setvalue)

        # make pointer-types compatible with the _ffi fast path
        if result._is_pointer_like():

            def _as_ffi_pointer_(self, ffitype):
                return as_ffi_pointer(self, ffitype)

            result._as_ffi_pointer_ = _as_ffi_pointer_

        return result