From 6636121950a08de9d437cc2d76ac272cdceb7ecc Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 13 Jul 2011 21:43:18 +0200 Subject: [PATCH] Close #4376: ctypes now supports nested structures in a endian different than the parent structure. Patch by Vlad Riscutia. --- Lib/ctypes/_endian.py | 16 ++++++++------ Lib/ctypes/test/test_byteswap.py | 36 ++++++++++++++++++++++---------- Misc/ACKS | 1 + Misc/NEWS | 3 +++ 4 files changed, 39 insertions(+), 17 deletions(-) diff --git a/Lib/ctypes/_endian.py b/Lib/ctypes/_endian.py index b48bda5c4f2..721b0d1c9e3 100644 --- a/Lib/ctypes/_endian.py +++ b/Lib/ctypes/_endian.py @@ -7,14 +7,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): diff --git a/Lib/ctypes/test/test_byteswap.py b/Lib/ctypes/test/test_byteswap.py index 83cb667ed14..3366ba6b286 100644 --- a/Lib/ctypes/test/test_byteswap.py +++ b/Lib/ctypes/test/test_byteswap.py @@ -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 + # nested structures with different byteorders - class T(Structure): - _fields_ = [("a", c_int), - ("b", c_int)] - class S(base): - pass - self.assertRaises(TypeError, setattr, S, "_fields_", [("s", T)]) + # 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. diff --git a/Misc/ACKS b/Misc/ACKS index 625317d50a0..ee9b3734aa1 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -735,6 +735,7 @@ Jan Pieter Riegel Armin Rigo Nicholas Riley Jean-Claude Rimbault +Vlad Riscutia Juan M. Bello Rivas Davide Rizzo Anthony Roach diff --git a/Misc/NEWS b/Misc/NEWS index 25c1f3cc67e..caa12a61d17 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -27,6 +27,9 @@ Core and Builtins Library ------- +- Issue #4376: ctypes now supports nested structures in a endian different than + the parent structure. Patch by Vlad Riscutia. + - Raise ValueError when attempting to set the _CHUNK_SIZE attribute of a TextIOWrapper to a huge value, not TypeError.