]> granicus.if.org Git - python/commitdiff
Close #4376: ctypes now supports nested structures in a endian different than
authorVictor Stinner <victor.stinner@haypocalc.com>
Wed, 13 Jul 2011 19:47:31 +0000 (21:47 +0200)
committerVictor Stinner <victor.stinner@haypocalc.com>
Wed, 13 Jul 2011 19:47:31 +0000 (21:47 +0200)
the parent structure. Patch by Vlad Riscutia.

Lib/ctypes/_endian.py
Lib/ctypes/test/test_byteswap.py
Misc/ACKS
Misc/NEWS

index 6de0d47b2ceae0c5f525cb951f18181e7caf88a1..e6b8556954f7dd9a29575072e312ac2af8e55042 100644 (file)
@@ -10,14 +10,18 @@ def _other_endian(typ):
     """Return the type with the 'other' byte order.  Simple types like
     c_int and so on already have __ctype_be__ and __ctype_le__
     attributes which contain the types, for more complicated types
-    only arrays are supported.
+    arrays and structures are supported.
     """
-    try:
+    # check _OTHER_ENDIAN attribute (present if typ is primitive type)
+    if hasattr(typ, _OTHER_ENDIAN):
         return getattr(typ, _OTHER_ENDIAN)
-    except AttributeError:
-        if type(typ) == _array_type:
-            return _other_endian(typ._type_) * typ._length_
-        raise TypeError("This type does not support other endian: %s" % typ)
+    # if typ is array
+    if isinstance(typ, _array_type):
+        return _other_endian(typ._type_) * typ._length_
+    # if typ is structure
+    if issubclass(typ, Structure):
+        return typ
+    raise TypeError("This type does not support other endian: %s" % typ)
 
 class _swapped_meta(type(Structure)):
     def __setattr__(self, attrname, value):
index 31637562333af7cd4a032f82ff5e0634764909bb..895c66086b44c7355ed1821008a826fc5f465ae9 100644 (file)
@@ -185,18 +185,32 @@ class Test(unittest.TestCase):
             self.assertRaises(TypeError, setattr, T, "_fields_", [("x", typ)])
 
     def test_struct_struct(self):
-        # Nested structures with different byte order not (yet) supported
-        if sys.byteorder == "little":
-            base = BigEndianStructure
-        else:
-            base = LittleEndianStructure
-
-        class T(Structure):
-            _fields_ = [("a", c_int),
-                        ("b", c_int)]
-        class S(base):
-            pass
-        self.assertRaises(TypeError, setattr, S, "_fields_", [("s", T)])
+        # nested structures with different byteorders
+
+        # create nested structures with given byteorders and set memory to data
+        def set_structures(endianness, nested_endianness, data):
+            class NestedStructure(nested_endianness):
+                _fields_ = [("x", c_uint32),
+                            ("y", c_uint32)]
+
+            class TestStructure(endianness):
+                _fields_ = [("point", NestedStructure)]
+
+            self.assertEqual(len(data), sizeof(TestStructure))
+            return cast(data, POINTER(TestStructure))[0]
+
+        for nested, data in (
+            (BigEndianStructure, b'\0\0\0\1\0\0\0\2'),
+            (LittleEndianStructure, b'\1\0\0\0\2\0\0\0'),
+        ):
+            for parent in (
+                BigEndianStructure,
+                LittleEndianStructure,
+                Structure,
+            ):
+                s = set_structures(parent, nested, data)
+                self.assertEqual(s.point.x, 1)
+                self.assertEqual(s.point.y, 2)
 
     def test_struct_fields_2(self):
         # standard packing in struct uses no alignment.
index 665f71fa08dc15623ba709e8d821786554c2d493..f7f5a34a5d77a7522cd75cdb7407f102de75d60b 100644 (file)
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -685,6 +685,7 @@ Jan Pieter Riegel
 Armin Rigo
 Nicholas Riley
 Jean-Claude Rimbault
+Vlad Riscutia
 Juan M. Bello Rivas
 Davide Rizzo
 Anthony Roach
index 4aa48aed47c0e0e50136f430d5489e5dfe0c6673..b282c13aa635faecc7b553fae1471d93883b5e34 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -30,6 +30,9 @@ Core and Builtins
 Library
 -------
 
+- Issue #4376: ctypes now supports nested structures in a endian different than
+  the parent structure. Patch by Vlad Riscutia.
+
 - Issue #12493: subprocess: Popen.communicate() now also handles EINTR errors
   if the process has only one pipe.