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_unsupported_byte_order(self): 174 175 fields = [ 176 ("a", c_ubyte), 177 ("b", c_byte), 178 ("c", c_short), 179 ("d", c_ushort), 180 ("e", c_int), 181 ("f", c_uint), 182 ("g", c_long), 183 ("h", c_ulong), 184 ("i", c_longlong), 185 ("k", c_ulonglong), 186 ("l", c_float), 187 ("m", c_double), 188 ("n", c_char), 189 ("b1", c_byte, 3), 190 ("b2", c_byte, 3), 191 ("b3", c_byte, 2), 192 ("a", c_int * 3 * 3 * 3) 193 ] 194 195 # these fields do not support different byte order: 196 for typ in c_wchar, c_void_p, POINTER(c_int): 197 with self.assertRaises(TypeError): 198 class T(BigEndianStructure if sys.byteorder == "little" else LittleEndianStructure): 199 _fields_ = fields + [("x", typ)] 200 201 202 def test_struct_struct(self): 203 # nested structures with different byteorders 204 205 # create nested structures with given byteorders and set memory to data 206 207 for nested, data in ( 208 (BigEndianStructure, b'\0\0\0\1\0\0\0\2'), 209 (LittleEndianStructure, b'\1\0\0\0\2\0\0\0'), 210 ): 211 for parent in ( 212 BigEndianStructure, 213 LittleEndianStructure, 214 Structure, 215 ): 216 class NestedStructure(nested): 217 _fields_ = [("x", c_uint32), 218 ("y", c_uint32)] 219 220 class TestStructure(parent): 221 _fields_ = [("point", NestedStructure)] 222 223 self.assertEqual(len(data), sizeof(TestStructure)) 224 ptr = POINTER(TestStructure) 225 s = cast(data, ptr)[0] 226 del ctypes._pointer_type_cache[TestStructure] 227 self.assertEqual(s.point.x, 1) 228 self.assertEqual(s.point.y, 2) 229 230 def test_struct_field_alignment(self): 231 # standard packing in struct uses no alignment. 232 # So, we have to align using pad bytes. 233 # 234 # Unaligned accesses will crash Python (on those platforms that 235 # don't allow it, like sparc solaris). 236 if sys.byteorder == "little": 237 base = BigEndianStructure 238 fmt = ">bxhid" 239 else: 240 base = LittleEndianStructure 241 fmt = "<bxhid" 242 243 class S(base): 244 _fields_ = [("b", c_byte), 245 ("h", c_short), 246 ("i", c_int), 247 ("d", c_double)] 248 249 s1 = S(0x12, 0x1234, 0x12345678, 3.14) 250 s2 = struct.pack(fmt, 0x12, 0x1234, 0x12345678, 3.14) 251 self.assertEqual(bin(s1), bin(s2)) 252 253 def test_unaligned_nonnative_struct_fields(self): 254 if sys.byteorder == "little": 255 base = BigEndianStructure 256 fmt = ">b h xi xd" 257 else: 258 base = LittleEndianStructure 259 fmt = "<b h xi xd" 260 261 class S(base): 262 _pack_ = 1 263 _fields_ = [("b", c_byte), 264 ("h", c_short), 265 266 ("_1", c_byte), 267 ("i", c_int), 268 269 ("_2", c_byte), 270 ("d", c_double)] 271 272 s1 = S() 273 s1.b = 0x12 274 s1.h = 0x1234 275 s1.i = 0x12345678 276 s1.d = 3.14 277 s2 = struct.pack(fmt, 0x12, 0x1234, 0x12345678, 3.14) 278 self.assertEqual(bin(s1), bin(s2)) 279 280 def test_unaligned_native_struct_fields(self): 281 if sys.byteorder == "little": 282 fmt = "<b h xi xd" 283 else: 284 base = LittleEndianStructure 285 fmt = ">b h xi xd" 286 287 class S(Structure): 288 _pack_ = 1 289 _fields_ = [("b", c_byte), 290 291 ("h", c_short), 292 293 ("_1", c_byte), 294 ("i", c_int), 295 296 ("_2", c_byte), 297 ("d", c_double)] 298 299 s1 = S() 300 s1.b = 0x12 301 s1.h = 0x1234 302 s1.i = 0x12345678 303 s1.d = 3.14 304 s2 = struct.pack(fmt, 0x12, 0x1234, 0x12345678, 3.14) 305 self.assertEqual(bin(s1), bin(s2)) 306 307 def test_union_fields_unsupported_byte_order(self): 308 309 fields = [ 310 ("a", c_ubyte), 311 ("b", c_byte), 312 ("c", c_short), 313 ("d", c_ushort), 314 ("e", c_int), 315 ("f", c_uint), 316 ("g", c_long), 317 ("h", c_ulong), 318 ("i", c_longlong), 319 ("k", c_ulonglong), 320 ("l", c_float), 321 ("m", c_double), 322 ("n", c_char), 323 ("b1", c_byte, 3), 324 ("b2", c_byte, 3), 325 ("b3", c_byte, 2), 326 ("a", c_int * 3 * 3 * 3) 327 ] 328 329 # these fields do not support different byte order: 330 for typ in c_wchar, c_void_p, POINTER(c_int): 331 with self.assertRaises(TypeError): 332 class T(BigEndianUnion if sys.byteorder == "little" else LittleEndianUnion): 333 _fields_ = fields + [("x", typ)] 334 335 def test_union_struct(self): 336 # nested structures in unions with different byteorders 337 338 # create nested structures in unions with given byteorders and set memory to data 339 340 for nested, data in ( 341 (BigEndianStructure, b'\0\0\0\1\0\0\0\2'), 342 (LittleEndianStructure, b'\1\0\0\0\2\0\0\0'), 343 ): 344 for parent in ( 345 BigEndianUnion, 346 LittleEndianUnion, 347 Union, 348 ): 349 class NestedStructure(nested): 350 _fields_ = [("x", c_uint32), 351 ("y", c_uint32)] 352 353 class TestUnion(parent): 354 _fields_ = [("point", NestedStructure)] 355 356 self.assertEqual(len(data), sizeof(TestUnion)) 357 ptr = POINTER(TestUnion) 358 s = cast(data, ptr)[0] 359 del ctypes._pointer_type_cache[TestUnion] 360 self.assertEqual(s.point.x, 1) 361 self.assertEqual(s.point.y, 2) 362 363if __name__ == "__main__": 364 unittest.main() 365