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