From: <fi...@us...> - 2009-04-29 04:35:26
|
Revision: 6274 http://jython.svn.sourceforge.net/jython/?rev=6274&view=rev Author: fijal Date: 2009-04-29 04:35:18 +0000 (Wed, 29 Apr 2009) Log Message: ----------- Progress on _rawffi. Supports more types (short, int, char), sizes are hardcoded so far. Rudimentary support for other things, enough to import slightly modified ctypes Modified Paths: -------------- branches/ctypes-via-rawffi/Lib/_rawffi.py branches/ctypes-via-rawffi/Lib/test/test__rawffi.py Modified: branches/ctypes-via-rawffi/Lib/_rawffi.py =================================================================== --- branches/ctypes-via-rawffi/Lib/_rawffi.py 2009-04-29 04:34:08 UTC (rev 6273) +++ branches/ctypes-via-rawffi/Lib/_rawffi.py 2009-04-29 04:35:18 UTC (rev 6274) @@ -1,57 +1,204 @@ import com.sun.jna as jna +from java.lang import Short, Character +import sys def get_libc(): return CDLL("c") -typecode_map = {'h': 2, 'H': 2} +FUNCFLAG_STDCALL = 0 +FUNCFLAG_CDECL = 1 # for WINAPI calls +FUNCFLAG_PYTHONAPI = 4 +# XXX hardcoded +typecode_map = {'h': 2, 'H': 2, + 'c': 1, 'p': 4, + 's': 4, 'P': 4, + 'i': 4, 'O': 4, + 'l': 4, 'L': 4, + 'f': 4, 'd': 8, + 'q': 8, 'Q': 8, + 'b': 1, 'B': 1, + 'z': 4, 'Z': 4, + 'u': 2} + +# set up of machine internals +_bits = 0 +_itest = 1 +_Ltest = 1L +while _itest == _Ltest and type(_itest) is int: + _itest *= 2 + _Ltest *= 2 + _bits += 1 + +LONG_BIT = _bits+1 +LONG_MASK = _Ltest*2-1 +LONG_TEST = _Ltest + +def intmask(n): + if isinstance(n, int): + return int(n) # possibly bool->int + n = long(n) + n &= LONG_MASK + if n >= LONG_TEST: + n -= 2*LONG_TEST + return int(n) + class Array(object): def __init__(self, typecode): self.typecode = typecode self.itemsize = typecode_map[typecode] - def __call__(self, size, autofree=False): + def allocate(self, size, autofree=False): if not autofree: - raise Exception + return ArrayInstanceNoAutoFree(self, size) return ArrayInstance(self, size) -class ArrayInstance(object): + def __call__(self, size, items=None, autofree=False): + res = self.allocate(size, autofree) + if items is not None: + for i, item in enumerate(items): + res[i] = item + return res + + def size_alignment(self, lgt): + return sizeof(self.typecode) * lgt, alignment(self.typecode) + +class ArrayInstanceNoAutoFree(object): def __init__(self, shape, size): self.shape = shape - self.alloc = jna.Memory(shape.itemsize * size) + self.alloc = jna.Pointer(jna.Memory.malloc(size * shape.itemsize)) def __setitem__(self, index, value): - self.alloc.setShort(index, value) + if self.shape.itemsize == 1: + self.alloc.setByte(index, ord(value)) + elif self.shape.itemsize == 2: + self.alloc.setShort(index, value) + elif self.shape.itemsize == 4: + self.alloc.setInt(index, value) + else: + xxx def __getitem__(self, index): - return self.alloc.getShort(index) + if self.shape.itemsize == 1: + return chr(self.alloc.getByte(index)) + elif self.shape.itemsize == 2: + return self.alloc.getShort(index) + elif self.shape.itemsize == 4: + return self.alloc.getInt(index) + else: + xxx + def free(self): + jna.Memory.free(self.alloc.peer) + + def byptr(self): + a = Array('p')(1) + a[0] = intmask(self.alloc.peer) + return a + + def getbuffer(self): + return self.alloc.peer + + def setbuffer(self, i): + self.alloc.peer = i + + buffer = property(getbuffer, setbuffer) + +class ArrayInstance(ArrayInstanceNoAutoFree): + def __del__(self): + self.free() + class FuncPtr(object): - def __init__(self, fn, name, argtypes, restype): - self.fn = fn - self.name = name + def __init__(self, fn, argtypes, restype, flags=0): + if isinstance(fn, (int, long)): + self.fn = jna.Function(jna.Pointer(fn), FUNCFLAG_STDCALL) + else: + self.fn = fn self.argtypes = argtypes self.restype = restype def __call__(self, *args): - container = Array('H')(1, autofree=True) - container[0] = self.fn.invokeInt([i[0] for i in args]) + container = Array(self.restype)(1, autofree=True) + _args = [self._convert(t, i[0]) for t, i in zip(self.argtypes, args)] + res = self.fn.invokeInt(_args) + if self.restype == 'c': + container[0] = chr(res) + else: + container[0] = res + return container + + def byptr(self): + a = Array('p')(1) + a[0] = intmask(self.fn.peer) + return a + def _convert(self, t, v): + if t == 'c': + return Character(v) + elif t == 'h': + return Short(v) + return v + +# XXX dummy obj +class CallbackPtr(object): + def __init__(self, tp, callable, args, result): + pass + + def byptr(self): + a = Array('p')(1) + a[0] = 0 + return a + class CDLL(object): def __init__(self, libname): self.lib = jna.NativeLibrary.getInstance(libname) self.cache = dict() - def ptr(self, name, argtypes, restype): + def ptr(self, name, argtypes, restype, flags=0): key = (name, tuple(argtypes), restype) try: return self.cache[key] except KeyError: fn = self.lib.getFunction(name) - fnp = FuncPtr(fn, name, argtypes, restype) + fnp = FuncPtr(fn, argtypes, restype, flags) self.cache[key] = fnp return fnp + def getaddressindll(self, symbol): + return self.lib.getFunction(symbol).peer +def sizeof(s): + return typecode_map[s] +def alignment(s): + return 1 + +def charp2string(s_p): + if s_p == 0: + return None + a = jna.Memory() + a.size = sys.maxint + a.peer = s_p + i = 0 + l = [] + while True: + c = chr(a.getByte(i)) + if c == '\x00': + return ''.join(l) + l.append(c) + i += 1 + +def charp2rawstring(s_p, size=-1): + if size == -1: + return charp2string(s_p) + else: + a = jna.Memory() + a.size = sys.maxint + a.peer = s_p + l = [] + for i in range(size): + c = chr(a.getByte(i)) + l.append(c) + i += 1 + return ''.join(l) Modified: branches/ctypes-via-rawffi/Lib/test/test__rawffi.py =================================================================== --- branches/ctypes-via-rawffi/Lib/test/test__rawffi.py 2009-04-29 04:34:08 UTC (rev 6273) +++ branches/ctypes-via-rawffi/Lib/test/test__rawffi.py 2009-04-29 04:35:18 UTC (rev 6274) @@ -3,11 +3,11 @@ # xxx - forces a skip in the case we haven't built ctypes_test module in ant (which is not yet a task as of now) -try: - import _rawffi - _rawffi.CDLL("ctypes_test") -except: - raise ImportError +#try: +import _rawffi +_rawffi.CDLL("ctypes_test") +#except: +# raise ImportError class RawFFITestCase(unittest.TestCase): @@ -47,6 +47,61 @@ #arg1.free() #arg2.free() + def test_short_addition_no_autofree(self): + import _rawffi + lib = _rawffi.CDLL(self.lib_name) + short_add = lib.ptr('add_shorts', ['h', 'h'], 'H') + A = _rawffi.Array('h') + arg1 = A(1) + arg2 = A(1) + arg1[0] = 1 + arg2[0] = 2 + res = short_add(arg1, arg2) + assert res[0] == 3 + arg1.free() + arg2.free() + + def test_getchar(self): + import _rawffi + lib = _rawffi.CDLL(self.lib_name) + get_char = lib.ptr('get_char', ['P', 'H'], 'c') + A = _rawffi.Array('c') + B = _rawffi.Array('H') + dupa = A(5, 'dupa') + dupaptr = dupa.byptr() + for i in range(4): + intptr = B(1) + intptr[0] = i + res = get_char(dupaptr, intptr) + assert res[0] == 'dupa'[i] + intptr.free() + dupaptr.free() + dupa.free() + + 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() + def test_main(): tests = [RawFFITestCase, ] This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |