Author: Armin Rigo <[email protected]>
Branch:
Changeset: r92265:c64a2e680657
Date: 2017-08-27 08:52 +0200
http://bitbucket.org/pypy/pypy/changeset/c64a2e680657/
Log: hg merge pypy_swappedbytes
PR #560
Adding swappedbytes support for ctypes.Structure
diff --git a/lib-python/2.7/ctypes/test/test_byteswap.py
b/lib-python/2.7/ctypes/test/test_byteswap.py
--- a/lib-python/2.7/ctypes/test/test_byteswap.py
+++ b/lib-python/2.7/ctypes/test/test_byteswap.py
@@ -23,7 +23,6 @@
setattr(bits, "i%s" % i, 1)
dump(bits)
- @xfail
def test_endian_short(self):
if sys.byteorder == "little":
self.assertIs(c_short.__ctype_le__, c_short)
@@ -51,7 +50,6 @@
self.assertEqual(bin(s), "3412")
self.assertEqual(s.value, 0x1234)
- @xfail
def test_endian_int(self):
if sys.byteorder == "little":
self.assertIs(c_int.__ctype_le__, c_int)
@@ -80,7 +78,6 @@
self.assertEqual(bin(s), "78563412")
self.assertEqual(s.value, 0x12345678)
- @xfail
def test_endian_longlong(self):
if sys.byteorder == "little":
self.assertIs(c_longlong.__ctype_le__, c_longlong)
@@ -109,7 +106,6 @@
self.assertEqual(bin(s), "EFCDAB9078563412")
self.assertEqual(s.value, 0x1234567890ABCDEF)
- @xfail
def test_endian_float(self):
if sys.byteorder == "little":
self.assertIs(c_float.__ctype_le__, c_float)
@@ -128,7 +124,6 @@
self.assertAlmostEqual(s.value, math.pi, 6)
self.assertEqual(bin(struct.pack(">f", math.pi)), bin(s))
- @xfail
def test_endian_double(self):
if sys.byteorder == "little":
self.assertIs(c_double.__ctype_le__, c_double)
@@ -156,7 +151,6 @@
self.assertIs(c_char.__ctype_le__, c_char)
self.assertIs(c_char.__ctype_be__, c_char)
- @xfail
def test_struct_fields_1(self):
if sys.byteorder == "little":
base = BigEndianStructure
@@ -221,7 +215,6 @@
self.assertEqual(s.point.x, 1)
self.assertEqual(s.point.y, 2)
- @xfail
def test_struct_fields_2(self):
# standard packing in struct uses no alignment.
# So, we have to align using pad bytes.
@@ -245,7 +238,6 @@
s2 = struct.pack(fmt, 0x12, 0x1234, 0x12345678, 3.14)
self.assertEqual(bin(s1), bin(s2))
- @xfail
def test_unaligned_nonnative_struct_fields(self):
if sys.byteorder == "little":
base = BigEndianStructure
diff --git a/lib-python/2.7/ctypes/test/test_unaligned_structures.py
b/lib-python/2.7/ctypes/test/test_unaligned_structures.py
--- a/lib-python/2.7/ctypes/test/test_unaligned_structures.py
+++ b/lib-python/2.7/ctypes/test/test_unaligned_structures.py
@@ -37,10 +37,7 @@
for typ in byteswapped_structures:
## print >> sys.stderr, typ.value
self.assertEqual(typ.value.offset, 1)
- try:
- o = typ()
- except NotImplementedError as e:
- self.skipTest(str(e)) # for PyPy
+ o = typ()
o.value = 4
self.assertEqual(o.value, 4)
diff --git a/lib_pypy/_ctypes/primitive.py b/lib_pypy/_ctypes/primitive.py
--- a/lib_pypy/_ctypes/primitive.py
+++ b/lib_pypy/_ctypes/primitive.py
@@ -61,6 +61,54 @@
pyobj_container = GlobalPyobjContainer()
+def swap_bytes(value, sizeof, typeof, get_or_set):
+ def swap_2():
+ return ((value >> 8) & 0x00FF) | ((value << 8) & 0xFF00)
+
+ def swap_4():
+ return ((value & 0x000000FF) << 24) | \
+ ((value & 0x0000FF00) << 8) | \
+ ((value & 0x00FF0000) >> 8) | \
+ ((value >> 24) & 0xFF)
+
+ def swap_8():
+ return ((value & 0x00000000000000FFL) << 56) | \
+ ((value & 0x000000000000FF00L) << 40) | \
+ ((value & 0x0000000000FF0000L) << 24) | \
+ ((value & 0x00000000FF000000L) << 8) | \
+ ((value & 0x000000FF00000000L) >> 8) | \
+ ((value & 0x0000FF0000000000L) >> 24) | \
+ ((value & 0x00FF000000000000L) >> 40) | \
+ ((value >> 56) & 0xFF)
+
+ def swap_double_float(typ):
+ from struct import pack, unpack
+ if get_or_set == 'set':
+ if sys.byteorder == 'little':
+ st = pack(''.join(['>', typ]), value)
+ else:
+ st = pack(''.join(['<', typ]), value)
+ return unpack(typ, st)[0]
+ else:
+ packed = pack(typ, value)
+ if sys.byteorder == 'little':
+ st = unpack(''.join(['>', typ]), packed)
+ else:
+ st = unpack(''.join(['<', typ]), packed)
+ return st[0]
+
+ if typeof in ('c_float', 'c_float_le', 'c_float_be'):
+ return swap_double_float('f')
+ elif typeof in ('c_double', 'c_double_le', 'c_double_be'):
+ return swap_double_float('d')
+ else:
+ if sizeof == 2:
+ return swap_2()
+ elif sizeof == 4:
+ return swap_4()
+ elif sizeof == 8:
+ return swap_8()
+
def generic_xxx_p_from_param(cls, value):
if value is None:
return cls(None)
@@ -271,6 +319,31 @@
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'):
+ from sys import byteorder
+ if 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
+ 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
+ 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
diff --git a/lib_pypy/_ctypes/structure.py b/lib_pypy/_ctypes/structure.py
--- a/lib_pypy/_ctypes/structure.py
+++ b/lib_pypy/_ctypes/structure.py
@@ -146,6 +146,7 @@
obj._buffer.__setattr__(self.name, arg)
+
def _set_shape(tp, rawfields, is_union=False):
tp._ffistruct_ = _rawffi.Structure(rawfields, is_union,
getattr(tp, '_pack_', 0))
@@ -240,19 +241,27 @@
res.__dict__['_index'] = -1
return res
-
class StructOrUnion(_CData):
__metaclass__ = StructOrUnionMeta
def __new__(cls, *args, **kwds):
from _ctypes import union
- self = super(_CData, cls).__new__(cls)
- if ('_abstract_' in cls.__dict__ or cls is Structure
+ if ('_abstract_' in cls.__dict__ or cls is Structure
or cls is union.Union):
raise TypeError("abstract class")
if hasattr(cls, '_swappedbytes_'):
- raise NotImplementedError("missing in PyPy: structure/union with "
- "swapped (non-native) byte ordering")
+ fields = [None] * len(cls._fields_)
+ for i in range(len(cls._fields_)):
+ if cls._fields_[i][1] ==
cls._fields_[i][1].__dict__.get('__ctype_be__', None):
+ swapped = cls._fields_[i][1].__dict__.get('__ctype_le__',
cls._fields_[i][1])
+ else:
+ swapped = cls._fields_[i][1].__dict__.get('__ctype_be__',
cls._fields_[i][1])
+ if len(cls._fields_[i]) < 3:
+ fields[i] = (cls._fields_[i][0], swapped)
+ else:
+ fields[i] = (cls._fields_[i][0], swapped,
cls._fields_[i][2])
+ names_and_fields(cls, fields, _CData,
cls.__dict__.get('_anonymous_', None))
+ self = super(_CData, cls).__new__(cls)
if hasattr(cls, '_ffistruct_'):
self.__dict__['_buffer'] = self._ffistruct_(autofree=True)
return self
diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py
b/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py
--- a/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py
+++ b/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py
@@ -22,7 +22,6 @@
assert X._fields_ == [("a", c_int)]
assert Y._fields_ == [("b", c_int)]
assert Z._fields_ == [("a", c_int)]
-
assert Y._names_ == ['a', 'b']
def test_subclass_delayed(self):
@@ -460,6 +459,38 @@
class X(Structure):
_fields_ = [(u"i", c_int)]
+ def test_swapped_bytes(self):
+ import sys
+
+ for i in [c_short, c_int, c_long, c_longlong,
+ c_float, c_double, c_ushort, c_uint,
+ c_ulong, c_ulonglong]:
+ FIELDS = [
+ ('n', i)
+ ]
+
+ class Native(Structure):
+ _fields_ = FIELDS
+
+ class Big(BigEndianStructure):
+ _fields_ = FIELDS
+
+ class Little(LittleEndianStructure):
+ _fields_ = FIELDS
+
+ def dostruct(c):
+ ba = create_string_buffer(sizeof(c))
+ ms = c.from_buffer(ba)
+ ms.n = 0xff00
+ return repr(ba[:])
+
+ if sys.byteorder == 'little':
+ assert dostruct(Native) == dostruct(Little)
+ assert dostruct(Native) != dostruct(Big)
+ else:
+ assert dostruct(Native) == dostruct(Big)
+ assert dostruct(Native) != dostruct(Little)
+
class TestPointerMember(BaseCTypesTestChecker):
def test_1(self):
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit