Index: Lib/_rawffi.py =================================================================== --- Lib/_rawffi.py (revision 6249) +++ Lib/_rawffi.py (working copy) @@ -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) Index: Lib/_ctypes/primitive.py =================================================================== --- Lib/_ctypes/primitive.py (revision 0) +++ Lib/_ctypes/primitive.py (revision 0) @@ -0,0 +1,314 @@ +import _rawffi +import weakref +import sys + +SIMPLE_TYPE_CHARS = "cbBhHiIlLdfuzZqQPXOv" + +from _ctypes.basics import _CData, _CDataMeta, cdata_from_address,\ + CArgObject +from _ctypes.builtin import ConvMode +from _ctypes.array import Array +from _ctypes.pointer import _Pointer + +class NULL(object): + pass +NULL = NULL() + +TP_TO_DEFAULT = { + 'c': 0, + 'u': 0, + 'b': 0, + 'B': 0, + 'h': 0, + 'H': 0, + 'i': 0, + 'I': 0, + 'l': 0, + 'L': 0, + 'q': 0, + 'Q': 0, + 'f': 0.0, + 'd': 0.0, + 'P': None, + # not part of struct + 'O': NULL, + 'z': None, + 'Z': None, +} + +if sys.platform == 'win32': + TP_TO_DEFAULT['X'] = NULL + TP_TO_DEFAULT['v'] = 0 + +DEFAULT_VALUE = object() + +class GlobalPyobjContainer(object): + def __init__(self): + self.objs = [] + + def add(self, obj): + num = len(self.objs) + self.objs.append(weakref.ref(obj)) + return num + + def get(self, num): + return self.objs[num]() + +pyobj_container = GlobalPyobjContainer() + +def generic_xxx_p_from_param(cls, value): + from _ctypes import Array, _Pointer + if value is None: + return cls(None) + if isinstance(value, basestring): + return cls(value) + if isinstance(value, _SimpleCData) and \ + type(value)._type_ in 'zZP': + return value + return None # eventually raise + +def from_param_char_p(cls, value): + "used by c_char_p and c_wchar_p subclasses" + res = generic_xxx_p_from_param(cls, 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 + +def from_param_void_p(cls, value): + "used by c_void_p subclasses" + res = generic_xxx_p_from_param(cls, value) + if res is not None: + return res + if isinstance(value, Array): + return value + if isinstance(value, _Pointer): + return cls.from_address(value._buffer.buffer) + +FROM_PARAM_BY_TYPE = { + 'z': from_param_char_p, + 'Z': from_param_char_p, + 'P': from_param_void_p, + } + +class SimpleType(_CDataMeta): + 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) + + 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 + from _ctypes import _wstring_at_addr + def _getvalue(self): + addr = self._buffer[0] + if addr == 0: + return None + else: + size = SysStringLen(addr) + return _wstring_at_addr(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 + + from_address = cdata_from_address + + def from_param(self, value): + from_param_f = FROM_PARAM_BY_TYPE.get(self._type_) + if from_param_f: + res = from_param_f(self, value) + if res is not None: + return res + + if isinstance(value, self): + return value + try: + return self(value) + except (TypeError, ValueError): + return super(SimpleType, self).from_param(value) + + def _CData_output(self, resbuffer, base=None, index=-1): + output = super(SimpleType, self)._CData_output(resbuffer, base, index) + return output.value + + def _sizeofinstances(self): + return _rawffi.sizeof(self._type_) + + def _alignmentofinstances(self): + return _rawffi.alignment(self._type_) + + def _is_pointer_like(self): + return self._type_ in "sPzUZXO" + +class _SimpleCData(_CData): + __metaclass__ = SimpleType + _type_ = 'i' + + def __init__(self, value=DEFAULT_VALUE): + self._buffer = self._ffiarray(1, autofree=True) + if value is not DEFAULT_VALUE: + self.value = value + + def _ensure_objects(self): + return None + + def _getvalue(self): + return self._buffer[0] + + def _setvalue(self, value): + self._buffer[0] = value + value = property(_getvalue, _setvalue) + del _getvalue, _setvalue + + def __ctypes_from_outparam__(self): + meta = type(type(self)) + if issubclass(meta, SimpleType) and meta != SimpleType: + return self + + return self.value + + def __repr__(self): + return "%s(%r)" % (type(self).__name__, self.value) + + def __nonzero__(self): + return self._buffer[0] not in (0, '\x00') Property changes on: Lib/_ctypes/primitive.py ___________________________________________________________________ Name: svn:eol-style + native Index: Lib/_ctypes/union.py =================================================================== --- Lib/_ctypes/union.py (revision 0) +++ Lib/_ctypes/union.py (revision 0) @@ -0,0 +1,115 @@ + + +import _rawffi +from _ctypes.basics import _CData, _CDataMeta, store_reference, keepalive_key +from _ctypes.basics import ensure_objects +from _ctypes.structure import round_up, names_and_fields, struct_getattr,\ + struct_setattr + + +def _set_shape(tp): + size = tp._sizeofinstances() + alignment = tp._alignmentofinstances() + tp._ffiopaque = _rawffi.Structure((size, alignment)) # opaque + tp._ffiargshape = tp._ffishape = (tp._ffiopaque, 1) + tp._fficompositesize = tp._ffiopaque.size + # we need to create an array of size one for each + # of our elements + tp._ffiarrays = {} + for name, field in tp._fieldtypes.iteritems(): + tp._ffiarrays[name] = _rawffi.Array(field.ctype._ffishape) + +class UnionMeta(_CDataMeta): + def __new__(self, name, cls, typedict): + res = type.__new__(self, name, cls, typedict) + if '_fields_' in typedict: + res._names, rawfields, res._fieldtypes = names_and_fields( + typedict['_fields_'], cls[0], True, + typedict.get('_anonymous_', None)) + _set_shape(res) + + def __init__(self): # don't allow arguments by now + if not hasattr(self, '_ffiarrays'): + raise TypeError("Cannot instantiate union, has no type") + # malloc size + size = self.__class__._sizeofinstances() + self.__dict__['_objects'] = {} + self.__dict__['_buffer'] = self._ffiopaque(autofree=True) + res.__init__ = __init__ + return res + + def _sizeofinstances(self): + if not hasattr(self, '_size_'): + self._size_ = max([field.size for field in + self._fieldtypes.values()] + [0]) + return self._size_ + + def _alignmentofinstances(self): + from ctypes import alignment + if not hasattr(self, '_alignment_'): + self._alignment_ = max([alignment(field.ctype) for field in + self._fieldtypes.values()] + [1]) + return self._alignment_ + + __getattr__ = struct_getattr + + def __setattr__(self, name, value): + if name == '_fields_': + if self.__dict__.get('_fields_', None): + raise AttributeError("_fields_ is final") + if self in [v for k, v in value]: + raise AttributeError("Union cannot contain itself") + self._names, rawfields, self._fieldtypes = names_and_fields( + value, self.__bases__[0], True, + self.__dict__.get('_anonymous_', None)) + _CDataMeta.__setattr__(self, '_fields_', value) + _set_shape(self) + _CDataMeta.__setattr__(self, name, value) + + def _CData_output(self, resarray, base=None, index=-1): + res = self.__new__(self) + ffiopaque = self._ffiopaque.fromaddress(resarray.buffer) + res.__dict__['_buffer'] = ffiopaque + res.__dict__['_base'] = base + res.__dict__['_index'] = index + return res + + def _CData_retval(self, resbuffer): + res = self.__new__(self) + res.__dict__['_buffer'] = resbuffer + res.__dict__['_base'] = None + res.__dict__['_index'] = -1 + return res + + +class Union(_CData): + __metaclass__ = UnionMeta + + def __getattr__(self, name): + try: + fieldtype = self._fieldtypes[name].ctype + except KeyError: + raise AttributeError(name) + val = self._ffiarrays[name].fromaddress(self._buffer.buffer, 1) + offset = self.__class__._fieldtypes[name].num + return fieldtype._CData_output(val, self, offset) + + def __setattr__(self, name, value): + try: + fieldtype = self._fieldtypes[name].ctype + except KeyError: + raise AttributeError(name) + if ensure_objects(value) is not None: + key = keepalive_key(getattr(self.__class__, name).num) + store_reference(self, key, value._objects) + arg = fieldtype._CData_value(value) + if fieldtype._fficompositesize is not None: + from ctypes import memmove + dest = self._buffer.buffer + memmove(dest, arg, fieldtype._fficompositesize) + else: + buf = self._ffiarrays[name].fromaddress(self._buffer.buffer, 1) + buf[0] = arg + + def _get_buffer_value(self): + return self._buffer.buffer Property changes on: Lib/_ctypes/union.py ___________________________________________________________________ Name: svn:eol-style + native Index: Lib/_ctypes/dll.py =================================================================== --- Lib/_ctypes/dll.py (revision 0) +++ Lib/_ctypes/dll.py (revision 0) @@ -0,0 +1,7 @@ +import _rawffi + +def dlopen(name, mode): + # XXX mode is ignored + if name is None: + return None # XXX this should return *all* loaded libs, dlopen(NULL) + return _rawffi.CDLL(name) Property changes on: Lib/_ctypes/dll.py ___________________________________________________________________ Name: svn:eol-style + native Index: Lib/_ctypes/dummy.py =================================================================== --- Lib/_ctypes/dummy.py (revision 0) +++ Lib/_ctypes/dummy.py (revision 0) @@ -0,0 +1,5 @@ +def dummyfunc(*args, **kwargs): + raise NotImplementedError("non-implemented ctypes function") + +resize = dummyfunc + Property changes on: Lib/_ctypes/dummy.py ___________________________________________________________________ Name: svn:eol-style + native Index: Lib/_ctypes/array.py =================================================================== --- Lib/_ctypes/array.py (revision 0) +++ Lib/_ctypes/array.py (revision 0) @@ -0,0 +1,209 @@ + +import _rawffi + +from _ctypes.basics import _CData, cdata_from_address, _CDataMeta, sizeof +from _ctypes.basics import keepalive_key, store_reference, ensure_objects +from _ctypes.basics import CArgObject +from _ctypes.builtin import _string_at_addr, _wstring_at_addr + +def _create_unicode(buffer, maxlength): + res = [] + for i in range(maxlength): + if buffer[i] == '\x00': + break + res.append(buffer[i]) + return u''.join(res) + +class ArrayMeta(_CDataMeta): + 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,)) + for i in range(len(val)): + self[i] = val[i] + if len(val) < self._length_: + self[len(val)] = '\x00' + res.value = property(getvalue, setvalue) + + def getraw(self): + return "".join([self[i] for i in range(self._length_)]) + + def setraw(self, buffer): + for i in range(len(buffer)): + self[i] = buffer[i] + res.raw = property(getraw, setraw) + elif subletter == 'u': + def getvalue(self): + # rawffi support anyone? + return _create_unicode(self._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,)) + for i in range(len(val)): + self[i] = val[i] + if len(val) < self._length_: + self[len(val)] = '\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 + + from_address = cdata_from_address + + def _sizeofinstances(self): + size, alignment = self._ffiarray.size_alignment(self._length_) + return size + + def _alignmentofinstances(self): + return self._type_._alignmentofinstances() + + def _CData_output(self, resarray, base=None, index=-1): + # this seems to be a string if we're array of char, surprise! + from ctypes import c_char, c_wchar, c_char_p, c_wchar_p + if self._type_ is c_char: + return _rawffi.charp2string(resarray.buffer, self._length_) + if self._type_ is c_wchar: + xxx + res = self.__new__(self) + ffiarray = self._ffiarray.fromaddress(resarray.buffer, self._length_) + res._buffer = ffiarray + res._base = base + res._index = index + return res + + def _CData_retval(self, resbuffer): + raise NotImplementedError + + def _CData_value(self, value): + # array accepts very strange parameters as part of structure + # or function argument... + from ctypes import c_char, c_wchar + if issubclass(self._type_, (c_char, c_wchar)): + if isinstance(value, basestring): + if len(value) > self._length_: + raise ValueError("Invalid length") + value = self(*value) + else: + if isinstance(value, tuple): + if len(value) > self._length_: + raise RuntimeError("Invalid length") + value = self(*value) + return _CDataMeta._CData_value(self, value) + +def array_get_slice_params(self, index): + if index.step is not None: + raise TypeError("3 arg slices not supported (for no reason)") + start = index.start or 0 + stop = index.stop or self._length_ + return start, stop + +def array_slice_setitem(self, index, value): + start, stop = self._get_slice_params(index) + if stop - start != len(value): + raise ValueError("Can only assign slices of the same length") + for i in range(start, stop): + self[i] = value[i - start] + +def array_slice_getitem(self, index): + start, stop = self._get_slice_params(index) + l = [self[i] for i in range(start, stop)] + letter = getattr(self._type_, '_type_', None) + if letter == 'c': + return "".join(l) + if letter == 'u': + return u"".join(l) + return l + +class Array(_CData): + __metaclass__ = ArrayMeta + _ffiargshape = 'P' + + def __init__(self, *args): + self._buffer = self._ffiarray(self._length_, autofree=True) + for i, arg in enumerate(args): + self[i] = arg + + def _fix_index(self, index): + if index < 0: + index += self._length_ + if 0 <= index < self._length_: + return index + else: + raise IndexError + + _get_slice_params = array_get_slice_params + _slice_getitem = array_slice_getitem + _slice_setitem = array_slice_setitem + + def _subarray(self, index): + """Return a _rawffi array of length 1 whose address is the same as + the index'th item of self.""" + address = self._buffer.itemaddress(index) + return self._ffiarray.fromaddress(address, 1) + + def __setitem__(self, index, value): + if isinstance(index, slice): + self._slice_setitem(index, value) + return + index = self._fix_index(index) + if ensure_objects(value) is not None: + store_reference(self, index, value._objects) + arg = self._type_._CData_value(value) + if self._type_._fficompositesize is None: + self._buffer[index] = arg + # something more sophisticated, cannot set field directly + else: + from ctypes import memmove + dest = self._buffer.itemaddress(index) + memmove(dest, arg, self._type_._fficompositesize) + + def __getitem__(self, index): + if isinstance(index, slice): + return self._slice_getitem(index) + index = self._fix_index(index) + return self._type_._CData_output(self._subarray(index), self, index) + + def __len__(self): + return self._length_ + + def _get_buffer_for_param(self): + return CArgObject(self._buffer.byptr()) + + def _get_buffer_value(self): + return self._buffer.buffer + +ARRAY_CACHE = {} + +def create_array_type(base, length): + if not isinstance(length, (int, long)): + raise TypeError("Can't multiply a ctypes type by a non-integer") + if length < 0: + raise ValueError("Array length must be >= 0") + key = (base, length) + try: + return ARRAY_CACHE[key] + except KeyError: + name = "%s_Array_%d" % (base.__name__, length) + tpdict = dict( + _length_ = length, + _type_ = base + ) + cls = ArrayMeta(name, (Array,), tpdict) + ARRAY_CACHE[key] = cls + return cls Property changes on: Lib/_ctypes/array.py ___________________________________________________________________ Name: svn:eol-style + native Index: Lib/_ctypes/__init__.py =================================================================== --- Lib/_ctypes/__init__.py (revision 0) +++ Lib/_ctypes/__init__.py (revision 0) @@ -0,0 +1,26 @@ +from _ctypes.dummy import resize +from _ctypes.basics import _CData, sizeof, alignment, byref, addressof,\ + ArgumentError, COMError +from _ctypes.primitive import _SimpleCData +from _ctypes.pointer import _Pointer, _cast_addr +from _ctypes.function import CFuncPtr +from _ctypes.dll import dlopen +from _ctypes.structure import Structure +from _ctypes.array import Array +from _ctypes.builtin import _memmove_addr, _string_at_addr, _memset_addr,\ + set_conversion_mode, _wstring_at_addr +from _ctypes.union import Union + +import os as _os + +if _os.name in ("nt", "ce"): + from _rawffi import FormatError + from _rawffi import check_HRESULT as _check_HRESULT + CopyComPointer = None # XXX + +from _rawffi import FUNCFLAG_STDCALL, FUNCFLAG_CDECL, FUNCFLAG_PYTHONAPI + +__version__ = '1.0.3' +#XXX platform dependant? +RTLD_LOCAL = 0 +RTLD_GLOBAL = 256 Property changes on: Lib/_ctypes/__init__.py ___________________________________________________________________ Name: svn:eol-style + native Index: Lib/_ctypes/pointer.py =================================================================== --- Lib/_ctypes/pointer.py (revision 0) +++ Lib/_ctypes/pointer.py (revision 0) @@ -0,0 +1,130 @@ + +import _rawffi +from _ctypes.basics import _CData, _CDataMeta, cdata_from_address +from _ctypes.basics import sizeof, byref, keepalive_key +from _ctypes.array import Array, array_get_slice_params, array_slice_getitem,\ + array_slice_setitem + +DEFAULT_VALUE = object() + +class PointerType(_CDataMeta): + def __new__(self, name, cls, typedict): + d = dict( + size = _rawffi.sizeof('P'), + align = _rawffi.alignment('P'), + length = 1, + _ffiargshape = 'P', + _ffishape = 'P', + _fficompositesize = None + ) + # XXX check if typedict['_type_'] is any sane + # XXX remember about paramfunc + obj = type.__new__(self, name, cls, typedict) + for k, v in d.iteritems(): + setattr(obj, k, v) + if '_type_' in typedict: + self.set_type(obj, typedict['_type_']) + else: + def __init__(self, value=None): + raise TypeError("%s has no type" % obj) + obj.__init__ = __init__ + return obj + + def from_param(self, value): + if value is None: + return self(None) + # If we expect POINTER(), but receive a instance, accept + # it by calling byref(). + if isinstance(value, self._type_): + return byref(value) + # Array instances are also pointers when the item types are the same. + if isinstance(value, (_Pointer, Array)): + if issubclass(type(value)._type_, self._type_): + return value + return _CDataMeta.from_param(self, value) + + def _sizeofinstances(self): + return _rawffi.sizeof('P') + + def _alignmentofinstances(self): + return _rawffi.alignment('P') + + def _is_pointer_like(self): + return True + + def set_type(self, TP): + ffiarray = _rawffi.Array('P') + def __init__(self, value=None): + self._buffer = ffiarray(1, autofree=True) + if value is not None: + self.contents = value + self._ffiarray = ffiarray + self.__init__ = __init__ + self._type_ = TP + + from_address = cdata_from_address + +class _Pointer(_CData): + __metaclass__ = PointerType + + def getcontents(self): + addr = self._buffer[0] + if addr == 0: + raise ValueError("NULL pointer access") + return self._type_.from_address(addr) + + def setcontents(self, value): + if not isinstance(value, self._type_): + raise TypeError("expected %s instead of %s" % ( + self._type_.__name__, type(value).__name__)) + self._objects = {keepalive_key(1):value} + if value._ensure_objects() is not None: + self._objects[keepalive_key(0)] = value._objects + value = value._buffer + self._buffer[0] = value + + _get_slice_params = array_get_slice_params + _slice_getitem = array_slice_getitem + + def _subarray(self, index=0): + """Return a _rawffi array of length 1 whose address is the same as + the index'th item to which self is pointing.""" + address = self._buffer[0] + address += index * sizeof(self._type_) + return self._type_.from_address(address)._buffer + + def __getitem__(self, index): + if isinstance(index, slice): + return self._slice_getitem(index) + return self._type_._CData_output(self._subarray(index), self, index) + + def __setitem__(self, index, value): + self._subarray(index)[0] = self._type_._CData_value(value) + + def __nonzero__(self): + return self._buffer[0] != 0 + + contents = property(getcontents, setcontents) + +def _cast_addr(obj, _, tp): + if not (isinstance(tp, _CDataMeta) and tp._is_pointer_like()): + raise TypeError("cast() argument 2 must be a pointer type, not %s" + % (tp,)) + if isinstance(obj, Array): + ptr = tp.__new__(tp) + ptr._buffer = tp._ffiarray(1, autofree=True) + ptr._buffer[0] = obj._buffer + return ptr + if isinstance(obj, (int, long)): + result = tp() + result._buffer[0] = obj + return result + if obj is None: + result = tp() + return result + if not (isinstance(obj, _CData) and type(obj)._is_pointer_like()): + raise TypeError("cast() argument 1 must be a pointer, not %s" + % (type(obj),)) + result = tp() + result._buffer[0] = obj._buffer[0] + return result Property changes on: Lib/_ctypes/pointer.py ___________________________________________________________________ Name: svn:eol-style + native Index: Lib/_ctypes/structure.py =================================================================== --- Lib/_ctypes/structure.py (revision 0) +++ Lib/_ctypes/structure.py (revision 0) @@ -0,0 +1,211 @@ + +import _rawffi +from _ctypes.basics import _CData, _CDataMeta, keepalive_key,\ + store_reference, ensure_objects, CArgObject +import inspect + +def round_up(size, alignment): + return (size + alignment - 1) & -alignment + +def size_alignment_pos(fields): + import ctypes + size = 0 + alignment = 1 + pos = [] + for fieldname, ctype in fields: + fieldsize = ctypes.sizeof(ctype) + fieldalignment = ctypes.alignment(ctype) + size = round_up(size, fieldalignment) + alignment = max(alignment, fieldalignment) + pos.append(size) + size += fieldsize + size = round_up(size, alignment) + return size, alignment, pos + +def names_and_fields(_fields_, superclass, zero_offset=False, anon=None): + if isinstance(_fields_, tuple): + _fields_ = list(_fields_) + for _, tp in _fields_: + if not isinstance(tp, _CDataMeta): + raise TypeError("Expected CData subclass, got %s" % (tp,)) + import ctypes + all_fields = _fields_[:] + for cls in inspect.getmro(superclass): + all_fields += getattr(cls, '_fields_', []) + names = [name for name, ctype in all_fields] + rawfields = [(name, ctype._ffishape) + for name, ctype in all_fields] + if not zero_offset: + _, _, pos = size_alignment_pos(all_fields) + else: + pos = [0] * len(all_fields) + fields = {} + for i, (name, ctype) in enumerate(all_fields): + fields[name] = Field(name, pos[i], ctypes.sizeof(ctype), ctype, i) + if anon: + resnames = [] + for i, (name, value) in enumerate(all_fields): + if name in anon: + for subname in value._names: + resnames.append(subname) + relpos = pos[i] + value._fieldtypes[subname].offset + subvalue = value._fieldtypes[subname].ctype + fields[subname] = Field(subname, relpos, + ctypes.sizeof(subvalue), subvalue, + i) + # XXX we never set rawfields here, let's wait for a test + else: + resnames.append(name) + names = resnames + return names, rawfields, fields + +class Field(object): + def __init__(self, name, offset, size, ctype, num): + for k in ('name', 'offset', 'size', 'ctype', 'num'): + self.__dict__[k] = locals()[k] + + def __setattr__(self, name, value): + raise AttributeError(name) + + def __repr__(self): + return "" % (self.name, self.offset, + self.size) + +# ________________________________________________________________ + +def _set_shape(tp, rawfields): + tp._ffistruct = _rawffi.Structure(rawfields) + tp._ffiargshape = tp._ffishape = (tp._ffistruct, 1) + tp._fficompositesize = tp._ffistruct.size + +def struct_getattr(self, name): + if hasattr(self, '_fieldtypes') and name in self._fieldtypes: + return self._fieldtypes[name] + return _CDataMeta.__getattribute__(self, name) + +def struct_setattr(self, name, value): + if name == '_fields_': + if self.__dict__.get('_fields_', None) is not None: + raise AttributeError("_fields_ is final") + if self in [v for k, v in value]: + raise AttributeError("Structure or union cannot contain itself") + self._names, rawfields, self._fieldtypes = names_and_fields( + value, self.__bases__[0], False, + self.__dict__.get('_anonymous_', None)) + _CDataMeta.__setattr__(self, '_fields_', value) + _set_shape(self, rawfields) + return + _CDataMeta.__setattr__(self, name, value) + +class StructureMeta(_CDataMeta): + def __new__(self, name, cls, typedict): + res = type.__new__(self, name, cls, typedict) + if '_fields_' in typedict: + if not hasattr(typedict.get('_anonymous_', []), '__iter__'): + raise TypeError("Anonymous field must be iterable") + for item in typedict.get('_anonymous_', []): + if item not in dict(typedict['_fields_']): + raise AttributeError("Anonymous field not found") + res._names, rawfields, res._fieldtypes = names_and_fields( + typedict['_fields_'], cls[0], False, + typedict.get('_anonymous_', None)) + _set_shape(res, rawfields) + + return res + + __getattr__ = struct_getattr + __setattr__ = struct_setattr + + def from_address(self, address): + instance = self.__new__(self) + instance.__dict__['_buffer'] = self._ffistruct.fromaddress(address) + return instance + + def _sizeofinstances(self): + if not hasattr(self, '_ffistruct'): + return 0 + return self._ffistruct.size + + def _alignmentofinstances(self): + return self._ffistruct.alignment + + def _CData_value(self, value): + if isinstance(value, tuple): + value = self(*value) + return _CDataMeta._CData_value(self, value) + + def _CData_output(self, resarray, base=None, index=-1): + res = self.__new__(self) + ffistruct = self._ffistruct.fromaddress(resarray.buffer) + res.__dict__['_buffer'] = ffistruct + res.__dict__['_base'] = base + res.__dict__['_index'] = index + return res + + def _CData_retval(self, resbuffer): + res = self.__new__(self) + res.__dict__['_buffer'] = resbuffer + res.__dict__['_base'] = None + res.__dict__['_index'] = -1 + return res + +class Structure(_CData): + __metaclass__ = StructureMeta + + def __new__(cls, *args, **kwds): + if not hasattr(cls, '_ffistruct'): + raise TypeError("Cannot instantiate structure, has no _fields_") + self = super(_CData, cls).__new__(cls, *args, **kwds) + self.__dict__['_buffer'] = self._ffistruct(autofree=True) + return self + + def __init__(self, *args, **kwds): + if len(args) > len(self._names): + raise TypeError("too many arguments") + for name, arg in zip(self._names, args): + if name in kwds: + raise TypeError("duplicate value for argument %r" % ( + name,)) + self.__setattr__(name, arg) + for name, arg in kwds.items(): + self.__setattr__(name, arg) + + 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) + + def __setattr__(self, name, value): + try: + fieldtype = self._fieldtypes[name].ctype + except KeyError: + return _CData.__setattr__(self, name, value) + if ensure_objects(value) is not None: + key = keepalive_key(getattr(self.__class__, name).num) + store_reference(self, key, value._objects) + arg = fieldtype._CData_value(value) + if fieldtype._fficompositesize is not None: + from ctypes import memmove + dest = self._buffer.fieldaddress(name) + memmove(dest, arg, fieldtype._fficompositesize) + else: + self._buffer.__setattr__(name, arg) + + def __getattribute__(self, name): + if name == '_fieldtypes': + return _CData.__getattribute__(self, '_fieldtypes') + try: + fieldtype = self._fieldtypes[name].ctype + except KeyError: + return _CData.__getattribute__(self, name) + offset = self.__class__._fieldtypes[name].num + suba = self._subarray(fieldtype, name) + return fieldtype._CData_output(suba, self, offset) + + def _get_buffer_for_param(self): + return self + + def _get_buffer_value(self): + return self._buffer.buffer Property changes on: Lib/_ctypes/structure.py ___________________________________________________________________ Name: svn:eol-style + native Index: Lib/_ctypes/basics.py =================================================================== --- Lib/_ctypes/basics.py (revision 0) +++ Lib/_ctypes/basics.py (revision 0) @@ -0,0 +1,166 @@ + +import _rawffi +import sys + +keepalive_key = str # XXX fix this when provided with test + +def ensure_objects(where): + try: + ensure = where._ensure_objects + except AttributeError: + return None + return ensure() + +def store_reference(where, base_key, target): + if '_index' not in where.__dict__: + # shortcut + where._ensure_objects()[str(base_key)] = target + return + key = [base_key] + while '_index' in where.__dict__: + key.append(where.__dict__['_index']) + where = where.__dict__['_base'] + real_key = ":".join([str(i) for i in key]) + where._ensure_objects()[real_key] = target + +class ArgumentError(Exception): + pass + +class COMError(Exception): + "Raised when a COM method call failed." + def __init__(self, hresult, text, details): + self.args = (hresult, text, details) + self.hresult = hresult + self.text = text + self.details = details + +class _CDataMeta(type): + def from_param(self, value): + if isinstance(value, self): + return value + try: + as_parameter = value._as_parameter_ + except AttributeError: + raise TypeError("expected %s instance instead of %s" % ( + self.__name__, type(value).__name__)) + else: + return self.from_param(as_parameter) + + def _CData_input(self, value): + """Used when data enters into ctypes from user code. 'value' is + some user-specified Python object, which is converted into a _rawffi + array of length 1 containing the same value according to the + type 'self'. + """ + cobj = self.from_param(value) + return cobj, cobj._get_buffer_for_param() + + def _CData_value(self, value): + cobj = self.from_param(value) + # we don't care here if this stuff will live afterwards, as we're + # interested only in value anyway + return cobj._get_buffer_value() + + def _CData_output(self, resbuffer, base=None, index=-1): + #assert isinstance(resbuffer, _rawffi.ArrayInstance) + """Used when data exits ctypes and goes into user code. + 'resbuffer' is a _rawffi array of length 1 containing the value, + and this returns a general Python object that corresponds. + """ + res = self.__new__(self) + res.__dict__['_buffer'] = resbuffer + res.__dict__['_base'] = base + res.__dict__['_index'] = index + return res + + def _CData_retval(self, resbuffer): + return self._CData_output(resbuffer) + + def __mul__(self, other): + from _ctypes.array import create_array_type + return create_array_type(self, other) + + __rmul__ = __mul__ + + def _is_pointer_like(self): + return False + + def in_dll(self, dll, name): + return self.from_address(dll._handle.getaddressindll(name)) + +class CArgObject(object): + """ simple wrapper around buffer, just for the case of freeing + it afterwards + """ + def __init__(self, buffer): + self._buffer = buffer + + def __del__(self): + self._buffer.free() + self._buffer = None + +class _CData(object): + """ The most basic object for all ctypes types + """ + __metaclass__ = _CDataMeta + _objects = None + + def __init__(self, *args, **kwds): + raise TypeError("%s has no type" % (type(self),)) + + def _ensure_objects(self): + if '_objects' not in self.__dict__: + if '_index' in self.__dict__: + return None + self.__dict__['_objects'] = {} + return self._objects + + def __ctypes_from_outparam__(self): + return self + + def _get_buffer_for_param(self): + return self + + def _get_buffer_value(self): + return self._buffer[0] + + def __buffer__(self): + return buffer(self._buffer) + + def _get_b_base(self): + return self._objects + _b_base_ = property(_get_b_base) + _b_needsfree_ = False + +def sizeof(tp): + if not isinstance(tp, _CDataMeta): + if isinstance(tp, _CData): + tp = type(tp) + else: + raise TypeError("ctypes type or instance expected, got %r" % ( + type(tp).__name__,)) + return tp._sizeofinstances() + +def alignment(tp): + if not isinstance(tp, _CDataMeta): + if isinstance(tp, _CData): + tp = type(tp) + else: + raise TypeError("ctypes type or instance expected, got %r" % ( + type(tp).__name__,)) + return tp._alignmentofinstances() + +def byref(cdata): + from ctypes import pointer + return pointer(cdata) + +def cdata_from_address(self, address): + # fix the address, in case it's unsigned + address = address & (sys.maxint * 2 + 1) + instance = self.__new__(self) + lgt = getattr(self, '_length_', 1) + instance._buffer = self._ffiarray.fromaddress(address, lgt) + return instance + +def addressof(tp): + return tp._buffer.buffer Property changes on: Lib/_ctypes/basics.py ___________________________________________________________________ Name: svn:eol-style + native Index: Lib/_ctypes/function.py =================================================================== --- Lib/_ctypes/function.py (revision 0) +++ Lib/_ctypes/function.py (revision 0) @@ -0,0 +1,368 @@ + +from _ctypes.basics import _CData, _CDataMeta, ArgumentError, keepalive_key +import _rawffi +import sys +import traceback + +# XXX this file needs huge refactoring I fear + +PARAMFLAG_FIN = 0x1 +PARAMFLAG_FOUT = 0x2 +PARAMFLAG_FLCID = 0x4 +def get_com_error(errcode, riid, pIunk): + "Win32 specific: build a COM Error exception" + # XXX need C support code + from _ctypes import COMError + return COMError(errcode, None, None) + +class CFuncPtrType(_CDataMeta): + # XXX write down here defaults and such things + + def _sizeofinstances(self): + return _rawffi.sizeof('P') + + def _alignmentofinstances(self): + return _rawffi.alignment('P') + + def _is_pointer_like(self): + return True + +class CFuncPtr(_CData): + __metaclass__ = CFuncPtrType + + _argtypes_ = None + _restype_ = None + _flags_ = 0 + _ffiargshape = 'P' + _ffishape = 'P' + _fficompositesize = None + _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@ + # 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 + return argtypes, wrapped_args + + def _build_result(self, restype, resbuffer, argtypes, argsandobjs): + """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""" + + retval = None + + if self._com_index: + if resbuffer[0] & 0x80000000: + raise get_com_error(resbuffer[0], + self._com_iid, argsandobjs[0][0]) + else: + retval = 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 + retval = checker(val) + elif not isinstance(restype, _CDataMeta): + retval = restype(resbuffer[0]) + else: + retval = restype._CData_retval(resbuffer) + + results = [] + if self._paramflags: + for argtype, (obj, _), paramflag in zip(argtypes[1:], argsandobjs[1:], + self._paramflags): + 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: + val = obj.__ctypes_from_outparam__() + results.append(val) + elif idlflag == PARAMFLAG_FIN | PARAMFLAG_FLCID: + pass + else: + raise NotImplementedError( + "paramflags = %s" % (paramflag,)) + + if results: + if len(results) == 1: + return results[0] + else: + return tuple(results) + + # No output parameter, return the actual function result. + return retval + + 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 Property changes on: Lib/_ctypes/function.py ___________________________________________________________________ Name: svn:eol-style + native Index: Lib/_ctypes/builtin.py =================================================================== --- Lib/_ctypes/builtin.py (revision 0) +++ Lib/_ctypes/builtin.py (revision 0) @@ -0,0 +1,35 @@ + +import _rawffi, sys + +class ConvMode: + encoding = 'ascii' + errors = 'strict' + +_memmove_addr = _rawffi.get_libc().getaddressindll('memmove') +_memset_addr = _rawffi.get_libc().getaddressindll('memset') + +def _string_at_addr(addr, lgt): + # address here can be almost anything + import ctypes + arg = ctypes.c_char_p._CData_value(addr) + return _rawffi.charp2rawstring(arg, lgt) + +def set_conversion_mode(encoding, errors): + old_cm = ConvMode.encoding, ConvMode.errors + ConvMode.errors = errors + ConvMode.encoding = encoding + return old_cm + +def _wstring_at_addr(addr, lgt): + import ctypes + arg = ctypes.c_wchar_p._CData_value(addr) + # XXX purely applevel + if lgt == -1: + lgt = sys.maxint + a = _rawffi.Array('u').fromaddress(arg, lgt) + res = [] + for i in xrange(lgt): + if lgt == sys.maxint and a[i] == '\x00': + break + res.append(a[i]) + return u''.join(res) Property changes on: Lib/_ctypes/builtin.py ___________________________________________________________________ Name: svn:eol-style + native Index: Lib/test/test__rawffi.py =================================================================== --- Lib/test/test__rawffi.py (revision 6249) +++ Lib/test/test__rawffi.py (working copy) @@ -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, ] Index: registry =================================================================== --- registry (revision 6249) +++ registry (working copy) @@ -45,7 +45,7 @@ # Setting this to false will allow Jython to provide access to # non-public fields, methods, and constructors of Java objects. -python.security.respectJavaAccessibility = true +python.security.respectJavaAccessibility = false # Setting this to true will force Jython will use the first module # found on sys.path where java File.isFile() returns true.