1import ctypes, ctypes.util, operator, sys 2from . import model 3 4if sys.version_info < (3,): 5 bytechr = chr 6else: 7 unicode = str 8 long = int 9 xrange = range 10 bytechr = lambda num: bytes([num]) 11 12class CTypesType(type): 13 pass 14 15class CTypesData(object): 16 __metaclass__ = CTypesType 17 __slots__ = ['__weakref__'] 18 __name__ = '<cdata>' 19 20 def __init__(self, *args): 21 raise TypeError("cannot instantiate %r" % (self.__class__,)) 22 23 @classmethod 24 def _newp(cls, init): 25 raise TypeError("expected a pointer or array ctype, got '%s'" 26 % (cls._get_c_name(),)) 27 28 @staticmethod 29 def _to_ctypes(value): 30 raise TypeError 31 32 @classmethod 33 def _arg_to_ctypes(cls, *value): 34 try: 35 ctype = cls._ctype 36 except AttributeError: 37 raise TypeError("cannot create an instance of %r" % (cls,)) 38 if value: 39 res = cls._to_ctypes(*value) 40 if not isinstance(res, ctype): 41 res = cls._ctype(res) 42 else: 43 res = cls._ctype() 44 return res 45 46 @classmethod 47 def _create_ctype_obj(cls, init): 48 if init is None: 49 return cls._arg_to_ctypes() 50 else: 51 return cls._arg_to_ctypes(init) 52 53 @staticmethod 54 def _from_ctypes(ctypes_value): 55 raise TypeError 56 57 @classmethod 58 def _get_c_name(cls, replace_with=''): 59 return cls._reftypename.replace(' &', replace_with) 60 61 @classmethod 62 def _fix_class(cls): 63 cls.__name__ = 'CData<%s>' % (cls._get_c_name(),) 64 cls.__qualname__ = 'CData<%s>' % (cls._get_c_name(),) 65 cls.__module__ = 'ffi' 66 67 def _get_own_repr(self): 68 raise NotImplementedError 69 70 def _addr_repr(self, address): 71 if address == 0: 72 return 'NULL' 73 else: 74 if address < 0: 75 address += 1 << (8*ctypes.sizeof(ctypes.c_void_p)) 76 return '0x%x' % address 77 78 def __repr__(self, c_name=None): 79 own = self._get_own_repr() 80 return '<cdata %r %s>' % (c_name or self._get_c_name(), own) 81 82 def _convert_to_address(self, BClass): 83 if BClass is None: 84 raise TypeError("cannot convert %r to an address" % ( 85 self._get_c_name(),)) 86 else: 87 raise TypeError("cannot convert %r to %r" % ( 88 self._get_c_name(), BClass._get_c_name())) 89 90 @classmethod 91 def _get_size(cls): 92 return ctypes.sizeof(cls._ctype) 93 94 def _get_size_of_instance(self): 95 return ctypes.sizeof(self._ctype) 96 97 @classmethod 98 def _cast_from(cls, source): 99 raise TypeError("cannot cast to %r" % (cls._get_c_name(),)) 100 101 def _cast_to_integer(self): 102 return self._convert_to_address(None) 103 104 @classmethod 105 def _alignment(cls): 106 return ctypes.alignment(cls._ctype) 107 108 def __iter__(self): 109 raise TypeError("cdata %r does not support iteration" % ( 110 self._get_c_name()),) 111 112 def _make_cmp(name): 113 cmpfunc = getattr(operator, name) 114 def cmp(self, other): 115 v_is_ptr = not isinstance(self, CTypesGenericPrimitive) 116 w_is_ptr = (isinstance(other, CTypesData) and 117 not isinstance(other, CTypesGenericPrimitive)) 118 if v_is_ptr and w_is_ptr: 119 return cmpfunc(self._convert_to_address(None), 120 other._convert_to_address(None)) 121 elif v_is_ptr or w_is_ptr: 122 return NotImplemented 123 else: 124 if isinstance(self, CTypesGenericPrimitive): 125 self = self._value 126 if isinstance(other, CTypesGenericPrimitive): 127 other = other._value 128 return cmpfunc(self, other) 129 cmp.func_name = name 130 return cmp 131 132 __eq__ = _make_cmp('__eq__') 133 __ne__ = _make_cmp('__ne__') 134 __lt__ = _make_cmp('__lt__') 135 __le__ = _make_cmp('__le__') 136 __gt__ = _make_cmp('__gt__') 137 __ge__ = _make_cmp('__ge__') 138 139 def __hash__(self): 140 return hash(self._convert_to_address(None)) 141 142 def _to_string(self, maxlen): 143 raise TypeError("string(): %r" % (self,)) 144 145 146class CTypesGenericPrimitive(CTypesData): 147 __slots__ = [] 148 149 def __hash__(self): 150 return hash(self._value) 151 152 def _get_own_repr(self): 153 return repr(self._from_ctypes(self._value)) 154 155 156class CTypesGenericArray(CTypesData): 157 __slots__ = [] 158 159 @classmethod 160 def _newp(cls, init): 161 return cls(init) 162 163 def __iter__(self): 164 for i in xrange(len(self)): 165 yield self[i] 166 167 def _get_own_repr(self): 168 return self._addr_repr(ctypes.addressof(self._blob)) 169 170 171class CTypesGenericPtr(CTypesData): 172 __slots__ = ['_address', '_as_ctype_ptr'] 173 _automatic_casts = False 174 kind = "pointer" 175 176 @classmethod 177 def _newp(cls, init): 178 return cls(init) 179 180 @classmethod 181 def _cast_from(cls, source): 182 if source is None: 183 address = 0 184 elif isinstance(source, CTypesData): 185 address = source._cast_to_integer() 186 elif isinstance(source, (int, long)): 187 address = source 188 else: 189 raise TypeError("bad type for cast to %r: %r" % 190 (cls, type(source).__name__)) 191 return cls._new_pointer_at(address) 192 193 @classmethod 194 def _new_pointer_at(cls, address): 195 self = cls.__new__(cls) 196 self._address = address 197 self._as_ctype_ptr = ctypes.cast(address, cls._ctype) 198 return self 199 200 def _get_own_repr(self): 201 try: 202 return self._addr_repr(self._address) 203 except AttributeError: 204 return '???' 205 206 def _cast_to_integer(self): 207 return self._address 208 209 def __nonzero__(self): 210 return bool(self._address) 211 __bool__ = __nonzero__ 212 213 @classmethod 214 def _to_ctypes(cls, value): 215 if not isinstance(value, CTypesData): 216 raise TypeError("unexpected %s object" % type(value).__name__) 217 address = value._convert_to_address(cls) 218 return ctypes.cast(address, cls._ctype) 219 220 @classmethod 221 def _from_ctypes(cls, ctypes_ptr): 222 address = ctypes.cast(ctypes_ptr, ctypes.c_void_p).value or 0 223 return cls._new_pointer_at(address) 224 225 @classmethod 226 def _initialize(cls, ctypes_ptr, value): 227 if value: 228 ctypes_ptr.contents = cls._to_ctypes(value).contents 229 230 def _convert_to_address(self, BClass): 231 if (BClass in (self.__class__, None) or BClass._automatic_casts 232 or self._automatic_casts): 233 return self._address 234 else: 235 return CTypesData._convert_to_address(self, BClass) 236 237 238class CTypesBaseStructOrUnion(CTypesData): 239 __slots__ = ['_blob'] 240 241 @classmethod 242 def _create_ctype_obj(cls, init): 243 # may be overridden 244 raise TypeError("cannot instantiate opaque type %s" % (cls,)) 245 246 def _get_own_repr(self): 247 return self._addr_repr(ctypes.addressof(self._blob)) 248 249 @classmethod 250 def _offsetof(cls, fieldname): 251 return getattr(cls._ctype, fieldname).offset 252 253 def _convert_to_address(self, BClass): 254 if getattr(BClass, '_BItem', None) is self.__class__: 255 return ctypes.addressof(self._blob) 256 else: 257 return CTypesData._convert_to_address(self, BClass) 258 259 @classmethod 260 def _from_ctypes(cls, ctypes_struct_or_union): 261 self = cls.__new__(cls) 262 self._blob = ctypes_struct_or_union 263 return self 264 265 @classmethod 266 def _to_ctypes(cls, value): 267 return value._blob 268 269 def __repr__(self, c_name=None): 270 return CTypesData.__repr__(self, c_name or self._get_c_name(' &')) 271 272 273class CTypesBackend(object): 274 275 PRIMITIVE_TYPES = { 276 'char': ctypes.c_char, 277 'short': ctypes.c_short, 278 'int': ctypes.c_int, 279 'long': ctypes.c_long, 280 'long long': ctypes.c_longlong, 281 'signed char': ctypes.c_byte, 282 'unsigned char': ctypes.c_ubyte, 283 'unsigned short': ctypes.c_ushort, 284 'unsigned int': ctypes.c_uint, 285 'unsigned long': ctypes.c_ulong, 286 'unsigned long long': ctypes.c_ulonglong, 287 'float': ctypes.c_float, 288 'double': ctypes.c_double, 289 '_Bool': ctypes.c_bool, 290 } 291 292 for _name in ['unsigned long long', 'unsigned long', 293 'unsigned int', 'unsigned short', 'unsigned char']: 294 _size = ctypes.sizeof(PRIMITIVE_TYPES[_name]) 295 PRIMITIVE_TYPES['uint%d_t' % (8*_size)] = PRIMITIVE_TYPES[_name] 296 if _size == ctypes.sizeof(ctypes.c_void_p): 297 PRIMITIVE_TYPES['uintptr_t'] = PRIMITIVE_TYPES[_name] 298 if _size == ctypes.sizeof(ctypes.c_size_t): 299 PRIMITIVE_TYPES['size_t'] = PRIMITIVE_TYPES[_name] 300 301 for _name in ['long long', 'long', 'int', 'short', 'signed char']: 302 _size = ctypes.sizeof(PRIMITIVE_TYPES[_name]) 303 PRIMITIVE_TYPES['int%d_t' % (8*_size)] = PRIMITIVE_TYPES[_name] 304 if _size == ctypes.sizeof(ctypes.c_void_p): 305 PRIMITIVE_TYPES['intptr_t'] = PRIMITIVE_TYPES[_name] 306 PRIMITIVE_TYPES['ptrdiff_t'] = PRIMITIVE_TYPES[_name] 307 if _size == ctypes.sizeof(ctypes.c_size_t): 308 PRIMITIVE_TYPES['ssize_t'] = PRIMITIVE_TYPES[_name] 309 310 311 def __init__(self): 312 self.RTLD_LAZY = 0 # not supported anyway by ctypes 313 self.RTLD_NOW = 0 314 self.RTLD_GLOBAL = ctypes.RTLD_GLOBAL 315 self.RTLD_LOCAL = ctypes.RTLD_LOCAL 316 317 def set_ffi(self, ffi): 318 self.ffi = ffi 319 320 def _get_types(self): 321 return CTypesData, CTypesType 322 323 def load_library(self, path, flags=0): 324 cdll = ctypes.CDLL(path, flags) 325 return CTypesLibrary(self, cdll) 326 327 def new_void_type(self): 328 class CTypesVoid(CTypesData): 329 __slots__ = [] 330 _reftypename = 'void &' 331 @staticmethod 332 def _from_ctypes(novalue): 333 return None 334 @staticmethod 335 def _to_ctypes(novalue): 336 if novalue is not None: 337 raise TypeError("None expected, got %s object" % 338 (type(novalue).__name__,)) 339 return None 340 CTypesVoid._fix_class() 341 return CTypesVoid 342 343 def new_primitive_type(self, name): 344 if name == 'wchar_t': 345 raise NotImplementedError(name) 346 ctype = self.PRIMITIVE_TYPES[name] 347 if name == 'char': 348 kind = 'char' 349 elif name in ('float', 'double'): 350 kind = 'float' 351 else: 352 if name in ('signed char', 'unsigned char'): 353 kind = 'byte' 354 elif name == '_Bool': 355 kind = 'bool' 356 else: 357 kind = 'int' 358 is_signed = (ctype(-1).value == -1) 359 # 360 def _cast_source_to_int(source): 361 if isinstance(source, (int, long, float)): 362 source = int(source) 363 elif isinstance(source, CTypesData): 364 source = source._cast_to_integer() 365 elif isinstance(source, bytes): 366 source = ord(source) 367 elif source is None: 368 source = 0 369 else: 370 raise TypeError("bad type for cast to %r: %r" % 371 (CTypesPrimitive, type(source).__name__)) 372 return source 373 # 374 kind1 = kind 375 class CTypesPrimitive(CTypesGenericPrimitive): 376 __slots__ = ['_value'] 377 _ctype = ctype 378 _reftypename = '%s &' % name 379 kind = kind1 380 381 def __init__(self, value): 382 self._value = value 383 384 @staticmethod 385 def _create_ctype_obj(init): 386 if init is None: 387 return ctype() 388 return ctype(CTypesPrimitive._to_ctypes(init)) 389 390 if kind == 'int' or kind == 'byte': 391 @classmethod 392 def _cast_from(cls, source): 393 source = _cast_source_to_int(source) 394 source = ctype(source).value # cast within range 395 return cls(source) 396 def __int__(self): 397 return self._value 398 399 if kind == 'bool': 400 @classmethod 401 def _cast_from(cls, source): 402 if not isinstance(source, (int, long, float)): 403 source = _cast_source_to_int(source) 404 return cls(bool(source)) 405 def __int__(self): 406 return self._value 407 408 if kind == 'char': 409 @classmethod 410 def _cast_from(cls, source): 411 source = _cast_source_to_int(source) 412 source = bytechr(source & 0xFF) 413 return cls(source) 414 def __int__(self): 415 return ord(self._value) 416 417 if kind == 'float': 418 @classmethod 419 def _cast_from(cls, source): 420 if isinstance(source, float): 421 pass 422 elif isinstance(source, CTypesGenericPrimitive): 423 if hasattr(source, '__float__'): 424 source = float(source) 425 else: 426 source = int(source) 427 else: 428 source = _cast_source_to_int(source) 429 source = ctype(source).value # fix precision 430 return cls(source) 431 def __int__(self): 432 return int(self._value) 433 def __float__(self): 434 return self._value 435 436 _cast_to_integer = __int__ 437 438 if kind == 'int' or kind == 'byte' or kind == 'bool': 439 @staticmethod 440 def _to_ctypes(x): 441 if not isinstance(x, (int, long)): 442 if isinstance(x, CTypesData): 443 x = int(x) 444 else: 445 raise TypeError("integer expected, got %s" % 446 type(x).__name__) 447 if ctype(x).value != x: 448 if not is_signed and x < 0: 449 raise OverflowError("%s: negative integer" % name) 450 else: 451 raise OverflowError("%s: integer out of bounds" 452 % name) 453 return x 454 455 if kind == 'char': 456 @staticmethod 457 def _to_ctypes(x): 458 if isinstance(x, bytes) and len(x) == 1: 459 return x 460 if isinstance(x, CTypesPrimitive): # <CData <char>> 461 return x._value 462 raise TypeError("character expected, got %s" % 463 type(x).__name__) 464 def __nonzero__(self): 465 return ord(self._value) != 0 466 else: 467 def __nonzero__(self): 468 return self._value != 0 469 __bool__ = __nonzero__ 470 471 if kind == 'float': 472 @staticmethod 473 def _to_ctypes(x): 474 if not isinstance(x, (int, long, float, CTypesData)): 475 raise TypeError("float expected, got %s" % 476 type(x).__name__) 477 return ctype(x).value 478 479 @staticmethod 480 def _from_ctypes(value): 481 return getattr(value, 'value', value) 482 483 @staticmethod 484 def _initialize(blob, init): 485 blob.value = CTypesPrimitive._to_ctypes(init) 486 487 if kind == 'char': 488 def _to_string(self, maxlen): 489 return self._value 490 if kind == 'byte': 491 def _to_string(self, maxlen): 492 return chr(self._value & 0xff) 493 # 494 CTypesPrimitive._fix_class() 495 return CTypesPrimitive 496 497 def new_pointer_type(self, BItem): 498 getbtype = self.ffi._get_cached_btype 499 if BItem is getbtype(model.PrimitiveType('char')): 500 kind = 'charp' 501 elif BItem in (getbtype(model.PrimitiveType('signed char')), 502 getbtype(model.PrimitiveType('unsigned char'))): 503 kind = 'bytep' 504 elif BItem is getbtype(model.void_type): 505 kind = 'voidp' 506 else: 507 kind = 'generic' 508 # 509 class CTypesPtr(CTypesGenericPtr): 510 __slots__ = ['_own'] 511 if kind == 'charp': 512 __slots__ += ['__as_strbuf'] 513 _BItem = BItem 514 if hasattr(BItem, '_ctype'): 515 _ctype = ctypes.POINTER(BItem._ctype) 516 _bitem_size = ctypes.sizeof(BItem._ctype) 517 else: 518 _ctype = ctypes.c_void_p 519 if issubclass(BItem, CTypesGenericArray): 520 _reftypename = BItem._get_c_name('(* &)') 521 else: 522 _reftypename = BItem._get_c_name(' * &') 523 524 def __init__(self, init): 525 ctypeobj = BItem._create_ctype_obj(init) 526 if kind == 'charp': 527 self.__as_strbuf = ctypes.create_string_buffer( 528 ctypeobj.value + b'\x00') 529 self._as_ctype_ptr = ctypes.cast( 530 self.__as_strbuf, self._ctype) 531 else: 532 self._as_ctype_ptr = ctypes.pointer(ctypeobj) 533 self._address = ctypes.cast(self._as_ctype_ptr, 534 ctypes.c_void_p).value 535 self._own = True 536 537 def __add__(self, other): 538 if isinstance(other, (int, long)): 539 return self._new_pointer_at(self._address + 540 other * self._bitem_size) 541 else: 542 return NotImplemented 543 544 def __sub__(self, other): 545 if isinstance(other, (int, long)): 546 return self._new_pointer_at(self._address - 547 other * self._bitem_size) 548 elif type(self) is type(other): 549 return (self._address - other._address) // self._bitem_size 550 else: 551 return NotImplemented 552 553 def __getitem__(self, index): 554 if getattr(self, '_own', False) and index != 0: 555 raise IndexError 556 return BItem._from_ctypes(self._as_ctype_ptr[index]) 557 558 def __setitem__(self, index, value): 559 self._as_ctype_ptr[index] = BItem._to_ctypes(value) 560 561 if kind == 'charp' or kind == 'voidp': 562 @classmethod 563 def _arg_to_ctypes(cls, *value): 564 if value and isinstance(value[0], bytes): 565 return ctypes.c_char_p(value[0]) 566 else: 567 return super(CTypesPtr, cls)._arg_to_ctypes(*value) 568 569 if kind == 'charp' or kind == 'bytep': 570 def _to_string(self, maxlen): 571 if maxlen < 0: 572 maxlen = sys.maxsize 573 p = ctypes.cast(self._as_ctype_ptr, 574 ctypes.POINTER(ctypes.c_char)) 575 n = 0 576 while n < maxlen and p[n] != b'\x00': 577 n += 1 578 return b''.join([p[i] for i in range(n)]) 579 580 def _get_own_repr(self): 581 if getattr(self, '_own', False): 582 return 'owning %d bytes' % ( 583 ctypes.sizeof(self._as_ctype_ptr.contents),) 584 return super(CTypesPtr, self)._get_own_repr() 585 # 586 if (BItem is self.ffi._get_cached_btype(model.void_type) or 587 BItem is self.ffi._get_cached_btype(model.PrimitiveType('char'))): 588 CTypesPtr._automatic_casts = True 589 # 590 CTypesPtr._fix_class() 591 return CTypesPtr 592 593 def new_array_type(self, CTypesPtr, length): 594 if length is None: 595 brackets = ' &[]' 596 else: 597 brackets = ' &[%d]' % length 598 BItem = CTypesPtr._BItem 599 getbtype = self.ffi._get_cached_btype 600 if BItem is getbtype(model.PrimitiveType('char')): 601 kind = 'char' 602 elif BItem in (getbtype(model.PrimitiveType('signed char')), 603 getbtype(model.PrimitiveType('unsigned char'))): 604 kind = 'byte' 605 else: 606 kind = 'generic' 607 # 608 class CTypesArray(CTypesGenericArray): 609 __slots__ = ['_blob', '_own'] 610 if length is not None: 611 _ctype = BItem._ctype * length 612 else: 613 __slots__.append('_ctype') 614 _reftypename = BItem._get_c_name(brackets) 615 _declared_length = length 616 _CTPtr = CTypesPtr 617 618 def __init__(self, init): 619 if length is None: 620 if isinstance(init, (int, long)): 621 len1 = init 622 init = None 623 elif kind == 'char' and isinstance(init, bytes): 624 len1 = len(init) + 1 # extra null 625 else: 626 init = tuple(init) 627 len1 = len(init) 628 self._ctype = BItem._ctype * len1 629 self._blob = self._ctype() 630 self._own = True 631 if init is not None: 632 self._initialize(self._blob, init) 633 634 @staticmethod 635 def _initialize(blob, init): 636 if isinstance(init, bytes): 637 init = [init[i:i+1] for i in range(len(init))] 638 else: 639 if isinstance(init, CTypesGenericArray): 640 if (len(init) != len(blob) or 641 not isinstance(init, CTypesArray)): 642 raise TypeError("length/type mismatch: %s" % (init,)) 643 init = tuple(init) 644 if len(init) > len(blob): 645 raise IndexError("too many initializers") 646 addr = ctypes.cast(blob, ctypes.c_void_p).value 647 PTR = ctypes.POINTER(BItem._ctype) 648 itemsize = ctypes.sizeof(BItem._ctype) 649 for i, value in enumerate(init): 650 p = ctypes.cast(addr + i * itemsize, PTR) 651 BItem._initialize(p.contents, value) 652 653 def __len__(self): 654 return len(self._blob) 655 656 def __getitem__(self, index): 657 if not (0 <= index < len(self._blob)): 658 raise IndexError 659 return BItem._from_ctypes(self._blob[index]) 660 661 def __setitem__(self, index, value): 662 if not (0 <= index < len(self._blob)): 663 raise IndexError 664 self._blob[index] = BItem._to_ctypes(value) 665 666 if kind == 'char' or kind == 'byte': 667 def _to_string(self, maxlen): 668 if maxlen < 0: 669 maxlen = len(self._blob) 670 p = ctypes.cast(self._blob, 671 ctypes.POINTER(ctypes.c_char)) 672 n = 0 673 while n < maxlen and p[n] != b'\x00': 674 n += 1 675 return b''.join([p[i] for i in range(n)]) 676 677 def _get_own_repr(self): 678 if getattr(self, '_own', False): 679 return 'owning %d bytes' % (ctypes.sizeof(self._blob),) 680 return super(CTypesArray, self)._get_own_repr() 681 682 def _convert_to_address(self, BClass): 683 if BClass in (CTypesPtr, None) or BClass._automatic_casts: 684 return ctypes.addressof(self._blob) 685 else: 686 return CTypesData._convert_to_address(self, BClass) 687 688 @staticmethod 689 def _from_ctypes(ctypes_array): 690 self = CTypesArray.__new__(CTypesArray) 691 self._blob = ctypes_array 692 return self 693 694 @staticmethod 695 def _arg_to_ctypes(value): 696 return CTypesPtr._arg_to_ctypes(value) 697 698 def __add__(self, other): 699 if isinstance(other, (int, long)): 700 return CTypesPtr._new_pointer_at( 701 ctypes.addressof(self._blob) + 702 other * ctypes.sizeof(BItem._ctype)) 703 else: 704 return NotImplemented 705 706 @classmethod 707 def _cast_from(cls, source): 708 raise NotImplementedError("casting to %r" % ( 709 cls._get_c_name(),)) 710 # 711 CTypesArray._fix_class() 712 return CTypesArray 713 714 def _new_struct_or_union(self, kind, name, base_ctypes_class): 715 # 716 class struct_or_union(base_ctypes_class): 717 pass 718 struct_or_union.__name__ = '%s_%s' % (kind, name) 719 kind1 = kind 720 # 721 class CTypesStructOrUnion(CTypesBaseStructOrUnion): 722 __slots__ = ['_blob'] 723 _ctype = struct_or_union 724 _reftypename = '%s &' % (name,) 725 _kind = kind = kind1 726 # 727 CTypesStructOrUnion._fix_class() 728 return CTypesStructOrUnion 729 730 def new_struct_type(self, name): 731 return self._new_struct_or_union('struct', name, ctypes.Structure) 732 733 def new_union_type(self, name): 734 return self._new_struct_or_union('union', name, ctypes.Union) 735 736 def complete_struct_or_union(self, CTypesStructOrUnion, fields, tp, 737 totalsize=-1, totalalignment=-1, sflags=0, 738 pack=0): 739 if totalsize >= 0 or totalalignment >= 0: 740 raise NotImplementedError("the ctypes backend of CFFI does not support " 741 "structures completed by verify(); please " 742 "compile and install the _cffi_backend module.") 743 struct_or_union = CTypesStructOrUnion._ctype 744 fnames = [fname for (fname, BField, bitsize) in fields] 745 btypes = [BField for (fname, BField, bitsize) in fields] 746 bitfields = [bitsize for (fname, BField, bitsize) in fields] 747 # 748 bfield_types = {} 749 cfields = [] 750 for (fname, BField, bitsize) in fields: 751 if bitsize < 0: 752 cfields.append((fname, BField._ctype)) 753 bfield_types[fname] = BField 754 else: 755 cfields.append((fname, BField._ctype, bitsize)) 756 bfield_types[fname] = Ellipsis 757 if sflags & 8: 758 struct_or_union._pack_ = 1 759 elif pack: 760 struct_or_union._pack_ = pack 761 struct_or_union._fields_ = cfields 762 CTypesStructOrUnion._bfield_types = bfield_types 763 # 764 @staticmethod 765 def _create_ctype_obj(init): 766 result = struct_or_union() 767 if init is not None: 768 initialize(result, init) 769 return result 770 CTypesStructOrUnion._create_ctype_obj = _create_ctype_obj 771 # 772 def initialize(blob, init): 773 if is_union: 774 if len(init) > 1: 775 raise ValueError("union initializer: %d items given, but " 776 "only one supported (use a dict if needed)" 777 % (len(init),)) 778 if not isinstance(init, dict): 779 if isinstance(init, (bytes, unicode)): 780 raise TypeError("union initializer: got a str") 781 init = tuple(init) 782 if len(init) > len(fnames): 783 raise ValueError("too many values for %s initializer" % 784 CTypesStructOrUnion._get_c_name()) 785 init = dict(zip(fnames, init)) 786 addr = ctypes.addressof(blob) 787 for fname, value in init.items(): 788 BField, bitsize = name2fieldtype[fname] 789 assert bitsize < 0, \ 790 "not implemented: initializer with bit fields" 791 offset = CTypesStructOrUnion._offsetof(fname) 792 PTR = ctypes.POINTER(BField._ctype) 793 p = ctypes.cast(addr + offset, PTR) 794 BField._initialize(p.contents, value) 795 is_union = CTypesStructOrUnion._kind == 'union' 796 name2fieldtype = dict(zip(fnames, zip(btypes, bitfields))) 797 # 798 for fname, BField, bitsize in fields: 799 if fname == '': 800 raise NotImplementedError("nested anonymous structs/unions") 801 if hasattr(CTypesStructOrUnion, fname): 802 raise ValueError("the field name %r conflicts in " 803 "the ctypes backend" % fname) 804 if bitsize < 0: 805 def getter(self, fname=fname, BField=BField, 806 offset=CTypesStructOrUnion._offsetof(fname), 807 PTR=ctypes.POINTER(BField._ctype)): 808 addr = ctypes.addressof(self._blob) 809 p = ctypes.cast(addr + offset, PTR) 810 return BField._from_ctypes(p.contents) 811 def setter(self, value, fname=fname, BField=BField): 812 setattr(self._blob, fname, BField._to_ctypes(value)) 813 # 814 if issubclass(BField, CTypesGenericArray): 815 setter = None 816 if BField._declared_length == 0: 817 def getter(self, fname=fname, BFieldPtr=BField._CTPtr, 818 offset=CTypesStructOrUnion._offsetof(fname), 819 PTR=ctypes.POINTER(BField._ctype)): 820 addr = ctypes.addressof(self._blob) 821 p = ctypes.cast(addr + offset, PTR) 822 return BFieldPtr._from_ctypes(p) 823 # 824 else: 825 def getter(self, fname=fname, BField=BField): 826 return BField._from_ctypes(getattr(self._blob, fname)) 827 def setter(self, value, fname=fname, BField=BField): 828 # xxx obscure workaround 829 value = BField._to_ctypes(value) 830 oldvalue = getattr(self._blob, fname) 831 setattr(self._blob, fname, value) 832 if value != getattr(self._blob, fname): 833 setattr(self._blob, fname, oldvalue) 834 raise OverflowError("value too large for bitfield") 835 setattr(CTypesStructOrUnion, fname, property(getter, setter)) 836 # 837 CTypesPtr = self.ffi._get_cached_btype(model.PointerType(tp)) 838 for fname in fnames: 839 if hasattr(CTypesPtr, fname): 840 raise ValueError("the field name %r conflicts in " 841 "the ctypes backend" % fname) 842 def getter(self, fname=fname): 843 return getattr(self[0], fname) 844 def setter(self, value, fname=fname): 845 setattr(self[0], fname, value) 846 setattr(CTypesPtr, fname, property(getter, setter)) 847 848 def new_function_type(self, BArgs, BResult, has_varargs): 849 nameargs = [BArg._get_c_name() for BArg in BArgs] 850 if has_varargs: 851 nameargs.append('...') 852 nameargs = ', '.join(nameargs) 853 # 854 class CTypesFunctionPtr(CTypesGenericPtr): 855 __slots__ = ['_own_callback', '_name'] 856 _ctype = ctypes.CFUNCTYPE(getattr(BResult, '_ctype', None), 857 *[BArg._ctype for BArg in BArgs], 858 use_errno=True) 859 _reftypename = BResult._get_c_name('(* &)(%s)' % (nameargs,)) 860 861 def __init__(self, init, error=None): 862 # create a callback to the Python callable init() 863 import traceback 864 assert not has_varargs, "varargs not supported for callbacks" 865 if getattr(BResult, '_ctype', None) is not None: 866 error = BResult._from_ctypes( 867 BResult._create_ctype_obj(error)) 868 else: 869 error = None 870 def callback(*args): 871 args2 = [] 872 for arg, BArg in zip(args, BArgs): 873 args2.append(BArg._from_ctypes(arg)) 874 try: 875 res2 = init(*args2) 876 res2 = BResult._to_ctypes(res2) 877 except: 878 traceback.print_exc() 879 res2 = error 880 if issubclass(BResult, CTypesGenericPtr): 881 if res2: 882 res2 = ctypes.cast(res2, ctypes.c_void_p).value 883 # .value: http://bugs.python.org/issue1574593 884 else: 885 res2 = None 886 #print repr(res2) 887 return res2 888 if issubclass(BResult, CTypesGenericPtr): 889 # The only pointers callbacks can return are void*s: 890 # http://bugs.python.org/issue5710 891 callback_ctype = ctypes.CFUNCTYPE( 892 ctypes.c_void_p, 893 *[BArg._ctype for BArg in BArgs], 894 use_errno=True) 895 else: 896 callback_ctype = CTypesFunctionPtr._ctype 897 self._as_ctype_ptr = callback_ctype(callback) 898 self._address = ctypes.cast(self._as_ctype_ptr, 899 ctypes.c_void_p).value 900 self._own_callback = init 901 902 @staticmethod 903 def _initialize(ctypes_ptr, value): 904 if value: 905 raise NotImplementedError("ctypes backend: not supported: " 906 "initializers for function pointers") 907 908 def __repr__(self): 909 c_name = getattr(self, '_name', None) 910 if c_name: 911 i = self._reftypename.index('(* &)') 912 if self._reftypename[i-1] not in ' )*': 913 c_name = ' ' + c_name 914 c_name = self._reftypename.replace('(* &)', c_name) 915 return CTypesData.__repr__(self, c_name) 916 917 def _get_own_repr(self): 918 if getattr(self, '_own_callback', None) is not None: 919 return 'calling %r' % (self._own_callback,) 920 return super(CTypesFunctionPtr, self)._get_own_repr() 921 922 def __call__(self, *args): 923 if has_varargs: 924 assert len(args) >= len(BArgs) 925 extraargs = args[len(BArgs):] 926 args = args[:len(BArgs)] 927 else: 928 assert len(args) == len(BArgs) 929 ctypes_args = [] 930 for arg, BArg in zip(args, BArgs): 931 ctypes_args.append(BArg._arg_to_ctypes(arg)) 932 if has_varargs: 933 for i, arg in enumerate(extraargs): 934 if arg is None: 935 ctypes_args.append(ctypes.c_void_p(0)) # NULL 936 continue 937 if not isinstance(arg, CTypesData): 938 raise TypeError( 939 "argument %d passed in the variadic part " 940 "needs to be a cdata object (got %s)" % 941 (1 + len(BArgs) + i, type(arg).__name__)) 942 ctypes_args.append(arg._arg_to_ctypes(arg)) 943 result = self._as_ctype_ptr(*ctypes_args) 944 return BResult._from_ctypes(result) 945 # 946 CTypesFunctionPtr._fix_class() 947 return CTypesFunctionPtr 948 949 def new_enum_type(self, name, enumerators, enumvalues, CTypesInt): 950 assert isinstance(name, str) 951 reverse_mapping = dict(zip(reversed(enumvalues), 952 reversed(enumerators))) 953 # 954 class CTypesEnum(CTypesInt): 955 __slots__ = [] 956 _reftypename = '%s &' % name 957 958 def _get_own_repr(self): 959 value = self._value 960 try: 961 return '%d: %s' % (value, reverse_mapping[value]) 962 except KeyError: 963 return str(value) 964 965 def _to_string(self, maxlen): 966 value = self._value 967 try: 968 return reverse_mapping[value] 969 except KeyError: 970 return str(value) 971 # 972 CTypesEnum._fix_class() 973 return CTypesEnum 974 975 def get_errno(self): 976 return ctypes.get_errno() 977 978 def set_errno(self, value): 979 ctypes.set_errno(value) 980 981 def string(self, b, maxlen=-1): 982 return b._to_string(maxlen) 983 984 def buffer(self, bptr, size=-1): 985 raise NotImplementedError("buffer() with ctypes backend") 986 987 def sizeof(self, cdata_or_BType): 988 if isinstance(cdata_or_BType, CTypesData): 989 return cdata_or_BType._get_size_of_instance() 990 else: 991 assert issubclass(cdata_or_BType, CTypesData) 992 return cdata_or_BType._get_size() 993 994 def alignof(self, BType): 995 assert issubclass(BType, CTypesData) 996 return BType._alignment() 997 998 def newp(self, BType, source): 999 if not issubclass(BType, CTypesData): 1000 raise TypeError 1001 return BType._newp(source) 1002 1003 def cast(self, BType, source): 1004 return BType._cast_from(source) 1005 1006 def callback(self, BType, source, error, onerror): 1007 assert onerror is None # XXX not implemented 1008 return BType(source, error) 1009 1010 _weakref_cache_ref = None 1011 1012 def gcp(self, cdata, destructor, size=0): 1013 if self._weakref_cache_ref is None: 1014 import weakref 1015 class MyRef(weakref.ref): 1016 def __eq__(self, other): 1017 myref = self() 1018 return self is other or ( 1019 myref is not None and myref is other()) 1020 def __ne__(self, other): 1021 return not (self == other) 1022 def __hash__(self): 1023 try: 1024 return self._hash 1025 except AttributeError: 1026 self._hash = hash(self()) 1027 return self._hash 1028 self._weakref_cache_ref = {}, MyRef 1029 weak_cache, MyRef = self._weakref_cache_ref 1030 1031 if destructor is None: 1032 try: 1033 del weak_cache[MyRef(cdata)] 1034 except KeyError: 1035 raise TypeError("Can remove destructor only on a object " 1036 "previously returned by ffi.gc()") 1037 return None 1038 1039 def remove(k): 1040 cdata, destructor = weak_cache.pop(k, (None, None)) 1041 if destructor is not None: 1042 destructor(cdata) 1043 1044 new_cdata = self.cast(self.typeof(cdata), cdata) 1045 assert new_cdata is not cdata 1046 weak_cache[MyRef(new_cdata, remove)] = (cdata, destructor) 1047 return new_cdata 1048 1049 typeof = type 1050 1051 def getcname(self, BType, replace_with): 1052 return BType._get_c_name(replace_with) 1053 1054 def typeoffsetof(self, BType, fieldname, num=0): 1055 if isinstance(fieldname, str): 1056 if num == 0 and issubclass(BType, CTypesGenericPtr): 1057 BType = BType._BItem 1058 if not issubclass(BType, CTypesBaseStructOrUnion): 1059 raise TypeError("expected a struct or union ctype") 1060 BField = BType._bfield_types[fieldname] 1061 if BField is Ellipsis: 1062 raise TypeError("not supported for bitfields") 1063 return (BField, BType._offsetof(fieldname)) 1064 elif isinstance(fieldname, (int, long)): 1065 if issubclass(BType, CTypesGenericArray): 1066 BType = BType._CTPtr 1067 if not issubclass(BType, CTypesGenericPtr): 1068 raise TypeError("expected an array or ptr ctype") 1069 BItem = BType._BItem 1070 offset = BItem._get_size() * fieldname 1071 if offset > sys.maxsize: 1072 raise OverflowError 1073 return (BItem, offset) 1074 else: 1075 raise TypeError(type(fieldname)) 1076 1077 def rawaddressof(self, BTypePtr, cdata, offset=None): 1078 if isinstance(cdata, CTypesBaseStructOrUnion): 1079 ptr = ctypes.pointer(type(cdata)._to_ctypes(cdata)) 1080 elif isinstance(cdata, CTypesGenericPtr): 1081 if offset is None or not issubclass(type(cdata)._BItem, 1082 CTypesBaseStructOrUnion): 1083 raise TypeError("unexpected cdata type") 1084 ptr = type(cdata)._to_ctypes(cdata) 1085 elif isinstance(cdata, CTypesGenericArray): 1086 ptr = type(cdata)._to_ctypes(cdata) 1087 else: 1088 raise TypeError("expected a <cdata 'struct-or-union'>") 1089 if offset: 1090 ptr = ctypes.cast( 1091 ctypes.c_void_p( 1092 ctypes.cast(ptr, ctypes.c_void_p).value + offset), 1093 type(ptr)) 1094 return BTypePtr._from_ctypes(ptr) 1095 1096 1097class CTypesLibrary(object): 1098 1099 def __init__(self, backend, cdll): 1100 self.backend = backend 1101 self.cdll = cdll 1102 1103 def load_function(self, BType, name): 1104 c_func = getattr(self.cdll, name) 1105 funcobj = BType._from_ctypes(c_func) 1106 funcobj._name = name 1107 return funcobj 1108 1109 def read_variable(self, BType, name): 1110 try: 1111 ctypes_obj = BType._ctype.in_dll(self.cdll, name) 1112 except AttributeError as e: 1113 raise NotImplementedError(e) 1114 return BType._from_ctypes(ctypes_obj) 1115 1116 def write_variable(self, BType, name, value): 1117 new_ctypes_obj = BType._to_ctypes(value) 1118 ctypes_obj = BType._ctype.in_dll(self.cdll, name) 1119 ctypes.memmove(ctypes.addressof(ctypes_obj), 1120 ctypes.addressof(new_ctypes_obj), 1121 ctypes.sizeof(BType._ctype)) 1122