1import sys, unittest, struct, math, ctypes 2from binascii import hexlify 3 4from ctypes import * 5 6def bin(s): 7 return hexlify(memoryview(s)).decode().upper() 8 9# Each *simple* type that supports different byte orders has an 10# __ctype_be__ attribute that specifies the same type in BIG ENDIAN 11# byte order, and a __ctype_le__ attribute that is the same type in 12# LITTLE ENDIAN byte order. 13# 14# For Structures and Unions, these types are created on demand. 15 16class Test(unittest.TestCase): 17 @unittest.skip('test disabled') 18 def test_X(self): 19 print(sys.byteorder, file=sys.stderr) 20 for i in range(32): 21 bits = BITS() 22 setattr(bits, "i%s" % i, 1) 23 dump(bits) 24 25 def test_slots(self): 26 class BigPoint(BigEndianStructure): 27 __slots__ = () 28 _fields_ = [("x", c_int), ("y", c_int)] 29 30 class LowPoint(LittleEndianStructure): 31 __slots__ = () 32 _fields_ = [("x", c_int), ("y", c_int)] 33 34 big = BigPoint() 35 little = LowPoint() 36 big.x = 4 37 big.y = 2 38 little.x = 2 39 little.y = 4 40 with self.assertRaises(AttributeError): 41 big.z = 42 42 with self.assertRaises(AttributeError): 43 little.z = 24 44 45 def test_endian_short(self): 46 if sys.byteorder == "little": 47 self.assertIs(c_short.__ctype_le__, c_short) 48 self.assertIs(c_short.__ctype_be__.__ctype_le__, c_short) 49 else: 50 self.assertIs(c_short.__ctype_be__, c_short) 51 self.assertIs(c_short.__ctype_le__.__ctype_be__, c_short) 52 s = c_short.__ctype_be__(0x1234) 53 self.assertEqual(bin(struct.pack(">h", 0x1234)), "1234") 54 self.assertEqual(bin(s), "1234") 55 self.assertEqual(s.value, 0x1234) 56 57 s = c_short.__ctype_le__(0x1234) 58 self.assertEqual(bin(struct.pack("<h", 0x1234)), "3412") 59 self.assertEqual(bin(s), "3412") 60 self.assertEqual(s.value, 0x1234) 61 62 s = c_ushort.__ctype_be__(0x1234) 63 self.assertEqual(bin(struct.pack(">h", 0x1234)), "1234") 64 self.assertEqual(bin(s), "1234") 65 self.assertEqual(s.value, 0x1234) 66 67 s = c_ushort.__ctype_le__(0x1234) 68 self.assertEqual(bin(struct.pack("<h", 0x1234)), "3412") 69 self.assertEqual(bin(s), "3412") 70 self.assertEqual(s.value, 0x1234) 71 72 def test_endian_int(self): 73 if sys.byteorder == "little": 74 self.assertIs(c_int.__ctype_le__, c_int) 75 self.assertIs(c_int.__ctype_be__.__ctype_le__, c_int) 76 else: 77 self.assertIs(c_int.__ctype_be__, c_int) 78 self.assertIs(c_int.__ctype_le__.__ctype_be__, c_int) 79 80 s = c_int.__ctype_be__(0x12345678) 81 self.assertEqual(bin(struct.pack(">i", 0x12345678)), "12345678") 82 self.assertEqual(bin(s), "12345678") 83 self.assertEqual(s.value, 0x12345678) 84 85 s = c_int.__ctype_le__(0x12345678) 86 self.assertEqual(bin(struct.pack("<i", 0x12345678)), "78563412") 87 self.assertEqual(bin(s), "78563412") 88 self.assertEqual(s.value, 0x12345678) 89 90 s = c_uint.__ctype_be__(0x12345678) 91 self.assertEqual(bin(struct.pack(">I", 0x12345678)), "12345678") 92 self.assertEqual(bin(s), "12345678") 93 self.assertEqual(s.value, 0x12345678) 94 95 s = c_uint.__ctype_le__(0x12345678) 96 self.assertEqual(bin(struct.pack("<I", 0x12345678)), "78563412") 97 self.assertEqual(bin(s), "78563412") 98 self.assertEqual(s.value, 0x12345678) 99 100 def test_endian_longlong(self): 101 if sys.byteorder == "little": 102 self.assertIs(c_longlong.__ctype_le__, c_longlong) 103 self.assertIs(c_longlong.__ctype_be__.__ctype_le__, c_longlong) 104 else: 105 self.assertIs(c_longlong.__ctype_be__, c_longlong) 106 self.assertIs(c_longlong.__ctype_le__.__ctype_be__, c_longlong) 107 108 s = c_longlong.__ctype_be__(0x1234567890ABCDEF) 109 self.assertEqual(bin(struct.pack(">q", 0x1234567890ABCDEF)), "1234567890ABCDEF") 110 self.assertEqual(bin(s), "1234567890ABCDEF") 111 self.assertEqual(s.value, 0x1234567890ABCDEF) 112 113 s = c_longlong.__ctype_le__(0x1234567890ABCDEF) 114 self.assertEqual(bin(struct.pack("<q", 0x1234567890ABCDEF)), "EFCDAB9078563412") 115 self.assertEqual(bin(s), "EFCDAB9078563412") 116 self.assertEqual(s.value, 0x1234567890ABCDEF) 117 118 s = c_ulonglong.__ctype_be__(0x1234567890ABCDEF) 119 self.assertEqual(bin(struct.pack(">Q", 0x1234567890ABCDEF)), "1234567890ABCDEF") 120 self.assertEqual(bin(s), "1234567890ABCDEF") 121 self.assertEqual(s.value, 0x1234567890ABCDEF) 122 123 s = c_ulonglong.__ctype_le__(0x1234567890ABCDEF) 124 self.assertEqual(bin(struct.pack("<Q", 0x1234567890ABCDEF)), "EFCDAB9078563412") 125 self.assertEqual(bin(s), "EFCDAB9078563412") 126 self.assertEqual(s.value, 0x1234567890ABCDEF) 127 128 def test_endian_float(self): 129 if sys.byteorder == "little": 130 self.assertIs(c_float.__ctype_le__, c_float) 131 self.assertIs(c_float.__ctype_be__.__ctype_le__, c_float) 132 else: 133 self.assertIs(c_float.__ctype_be__, c_float) 134 self.assertIs(c_float.__ctype_le__.__ctype_be__, c_float) 135 s = c_float(math.pi) 136 self.assertEqual(bin(struct.pack("f", math.pi)), bin(s)) 137 # Hm, what's the precision of a float compared to a double? 138 self.assertAlmostEqual(s.value, math.pi, places=6) 139 s = c_float.__ctype_le__(math.pi) 140 self.assertAlmostEqual(s.value, math.pi, places=6) 141 self.assertEqual(bin(struct.pack("<f", math.pi)), bin(s)) 142 s = c_float.__ctype_be__(math.pi) 143 self.assertAlmostEqual(s.value, math.pi, places=6) 144 self.assertEqual(bin(struct.pack(">f", math.pi)), bin(s)) 145 146 def test_endian_double(self): 147 if sys.byteorder == "little": 148 self.assertIs(c_double.__ctype_le__, c_double) 149 self.assertIs(c_double.__ctype_be__.__ctype_le__, c_double) 150 else: 151 self.assertIs(c_double.__ctype_be__, c_double) 152 self.assertIs(c_double.__ctype_le__.__ctype_be__, c_double) 153 s = c_double(math.pi) 154 self.assertEqual(s.value, math.pi) 155 self.assertEqual(bin(struct.pack("d", math.pi)), bin(s)) 156 s = c_double.__ctype_le__(math.pi) 157 self.assertEqual(s.value, math.pi) 158 self.assertEqual(bin(struct.pack("<d", math.pi)), bin(s)) 159 s = c_double.__ctype_be__(math.pi) 160 self.assertEqual(s.value, math.pi) 161 self.assertEqual(bin(struct.pack(">d", math.pi)), bin(s)) 162 163 def test_endian_other(self): 164 self.assertIs(c_byte.__ctype_le__, c_byte) 165 self.assertIs(c_byte.__ctype_be__, c_byte) 166 167 self.assertIs(c_ubyte.__ctype_le__, c_ubyte) 168 self.assertIs(c_ubyte.__ctype_be__, c_ubyte) 169 170 self.assertIs(c_char.__ctype_le__, c_char) 171 self.assertIs(c_char.__ctype_be__, c_char) 172 173 def test_struct_fields_1(self): 174 if sys.byteorder == "little": 175 base = BigEndianStructure 176 else: 177 base = LittleEndianStructure 178 179 class T(base): 180 pass 181 _fields_ = [("a", c_ubyte), 182 ("b", c_byte), 183 ("c", c_short), 184 ("d", c_ushort), 185 ("e", c_int), 186 ("f", c_uint), 187 ("g", c_long), 188 ("h", c_ulong), 189 ("i", c_longlong), 190 ("k", c_ulonglong), 191 ("l", c_float), 192 ("m", c_double), 193 ("n", c_char), 194 195 ("b1", c_byte, 3), 196 ("b2", c_byte, 3), 197 ("b3", c_byte, 2), 198 ("a", c_int * 3 * 3 * 3)] 199 T._fields_ = _fields_ 200 201 # these fields do not support different byte order: 202 for typ in c_wchar, c_void_p, POINTER(c_int): 203 _fields_.append(("x", typ)) 204 class T(base): 205 pass 206 self.assertRaises(TypeError, setattr, T, "_fields_", [("x", typ)]) 207 208 def test_struct_struct(self): 209 # nested structures with different byteorders 210 211 # create nested structures with given byteorders and set memory to data 212 213 for nested, data in ( 214 (BigEndianStructure, b'\0\0\0\1\0\0\0\2'), 215 (LittleEndianStructure, b'\1\0\0\0\2\0\0\0'), 216 ): 217 for parent in ( 218 BigEndianStructure, 219 LittleEndianStructure, 220 Structure, 221 ): 222 class NestedStructure(nested): 223 _fields_ = [("x", c_uint32), 224 ("y", c_uint32)] 225 226 class TestStructure(parent): 227 _fields_ = [("point", NestedStructure)] 228 229 self.assertEqual(len(data), sizeof(TestStructure)) 230 ptr = POINTER(TestStructure) 231 s = cast(data, ptr)[0] 232 del ctypes._pointer_type_cache[TestStructure] 233 self.assertEqual(s.point.x, 1) 234 self.assertEqual(s.point.y, 2) 235 236 def test_struct_fields_2(self): 237 # standard packing in struct uses no alignment. 238 # So, we have to align using pad bytes. 239 # 240 # Unaligned accesses will crash Python (on those platforms that 241 # don't allow it, like sparc solaris). 242 if sys.byteorder == "little": 243 base = BigEndianStructure 244 fmt = ">bxhid" 245 else: 246 base = LittleEndianStructure 247 fmt = "<bxhid" 248 249 class S(base): 250 _fields_ = [("b", c_byte), 251 ("h", c_short), 252 ("i", c_int), 253 ("d", c_double)] 254 255 s1 = S(0x12, 0x1234, 0x12345678, 3.14) 256 s2 = struct.pack(fmt, 0x12, 0x1234, 0x12345678, 3.14) 257 self.assertEqual(bin(s1), bin(s2)) 258 259 def test_unaligned_nonnative_struct_fields(self): 260 if sys.byteorder == "little": 261 base = BigEndianStructure 262 fmt = ">b h xi xd" 263 else: 264 base = LittleEndianStructure 265 fmt = "<b h xi xd" 266 267 class S(base): 268 _pack_ = 1 269 _fields_ = [("b", c_byte), 270 271 ("h", c_short), 272 273 ("_1", c_byte), 274 ("i", c_int), 275 276 ("_2", c_byte), 277 ("d", c_double)] 278 279 s1 = S() 280 s1.b = 0x12 281 s1.h = 0x1234 282 s1.i = 0x12345678 283 s1.d = 3.14 284 s2 = struct.pack(fmt, 0x12, 0x1234, 0x12345678, 3.14) 285 self.assertEqual(bin(s1), bin(s2)) 286 287 def test_unaligned_native_struct_fields(self): 288 if sys.byteorder == "little": 289 fmt = "<b h xi xd" 290 else: 291 base = LittleEndianStructure 292 fmt = ">b h xi xd" 293 294 class S(Structure): 295 _pack_ = 1 296 _fields_ = [("b", c_byte), 297 298 ("h", c_short), 299 300 ("_1", c_byte), 301 ("i", c_int), 302 303 ("_2", c_byte), 304 ("d", c_double)] 305 306 s1 = S() 307 s1.b = 0x12 308 s1.h = 0x1234 309 s1.i = 0x12345678 310 s1.d = 3.14 311 s2 = struct.pack(fmt, 0x12, 0x1234, 0x12345678, 3.14) 312 self.assertEqual(bin(s1), bin(s2)) 313 314if __name__ == "__main__": 315 unittest.main() 316