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

Reply via email to