1"""create and manipulate C data types in Python""" 2 3import os as _os, sys as _sys 4import types as _types 5 6__version__ = "1.1.0" 7 8from _ctypes import Union, Structure, Array 9from _ctypes import _Pointer 10from _ctypes import CFuncPtr as _CFuncPtr 11from _ctypes import __version__ as _ctypes_version 12from _ctypes import RTLD_LOCAL, RTLD_GLOBAL 13from _ctypes import ArgumentError 14from _ctypes import SIZEOF_TIME_T 15 16from struct import calcsize as _calcsize 17 18if __version__ != _ctypes_version: 19 raise Exception("Version number mismatch", __version__, _ctypes_version) 20 21if _os.name == "nt": 22 from _ctypes import FormatError 23 24DEFAULT_MODE = RTLD_LOCAL 25if _os.name == "posix" and _sys.platform == "darwin": 26 # On OS X 10.3, we use RTLD_GLOBAL as default mode 27 # because RTLD_LOCAL does not work at least on some 28 # libraries. OS X 10.3 is Darwin 7, so we check for 29 # that. 30 31 if int(_os.uname().release.split('.')[0]) < 8: 32 DEFAULT_MODE = RTLD_GLOBAL 33 34from _ctypes import FUNCFLAG_CDECL as _FUNCFLAG_CDECL, \ 35 FUNCFLAG_PYTHONAPI as _FUNCFLAG_PYTHONAPI, \ 36 FUNCFLAG_USE_ERRNO as _FUNCFLAG_USE_ERRNO, \ 37 FUNCFLAG_USE_LASTERROR as _FUNCFLAG_USE_LASTERROR 38 39# WINOLEAPI -> HRESULT 40# WINOLEAPI_(type) 41# 42# STDMETHODCALLTYPE 43# 44# STDMETHOD(name) 45# STDMETHOD_(type, name) 46# 47# STDAPICALLTYPE 48 49def create_string_buffer(init, size=None): 50 """create_string_buffer(aBytes) -> character array 51 create_string_buffer(anInteger) -> character array 52 create_string_buffer(aBytes, anInteger) -> character array 53 """ 54 if isinstance(init, bytes): 55 if size is None: 56 size = len(init)+1 57 _sys.audit("ctypes.create_string_buffer", init, size) 58 buftype = c_char * size 59 buf = buftype() 60 buf.value = init 61 return buf 62 elif isinstance(init, int): 63 _sys.audit("ctypes.create_string_buffer", None, init) 64 buftype = c_char * init 65 buf = buftype() 66 return buf 67 raise TypeError(init) 68 69# Alias to create_string_buffer() for backward compatibility 70c_buffer = create_string_buffer 71 72_c_functype_cache = {} 73def CFUNCTYPE(restype, *argtypes, **kw): 74 """CFUNCTYPE(restype, *argtypes, 75 use_errno=False, use_last_error=False) -> function prototype. 76 77 restype: the result type 78 argtypes: a sequence specifying the argument types 79 80 The function prototype can be called in different ways to create a 81 callable object: 82 83 prototype(integer address) -> foreign function 84 prototype(callable) -> create and return a C callable function from callable 85 prototype(integer index, method name[, paramflags]) -> foreign function calling a COM method 86 prototype((ordinal number, dll object)[, paramflags]) -> foreign function exported by ordinal 87 prototype((function name, dll object)[, paramflags]) -> foreign function exported by name 88 """ 89 flags = _FUNCFLAG_CDECL 90 if kw.pop("use_errno", False): 91 flags |= _FUNCFLAG_USE_ERRNO 92 if kw.pop("use_last_error", False): 93 flags |= _FUNCFLAG_USE_LASTERROR 94 if kw: 95 raise ValueError("unexpected keyword argument(s) %s" % kw.keys()) 96 97 try: 98 return _c_functype_cache[(restype, argtypes, flags)] 99 except KeyError: 100 pass 101 102 class CFunctionType(_CFuncPtr): 103 _argtypes_ = argtypes 104 _restype_ = restype 105 _flags_ = flags 106 _c_functype_cache[(restype, argtypes, flags)] = CFunctionType 107 return CFunctionType 108 109if _os.name == "nt": 110 from _ctypes import LoadLibrary as _dlopen 111 from _ctypes import FUNCFLAG_STDCALL as _FUNCFLAG_STDCALL 112 113 _win_functype_cache = {} 114 def WINFUNCTYPE(restype, *argtypes, **kw): 115 # docstring set later (very similar to CFUNCTYPE.__doc__) 116 flags = _FUNCFLAG_STDCALL 117 if kw.pop("use_errno", False): 118 flags |= _FUNCFLAG_USE_ERRNO 119 if kw.pop("use_last_error", False): 120 flags |= _FUNCFLAG_USE_LASTERROR 121 if kw: 122 raise ValueError("unexpected keyword argument(s) %s" % kw.keys()) 123 124 try: 125 return _win_functype_cache[(restype, argtypes, flags)] 126 except KeyError: 127 pass 128 129 class WinFunctionType(_CFuncPtr): 130 _argtypes_ = argtypes 131 _restype_ = restype 132 _flags_ = flags 133 _win_functype_cache[(restype, argtypes, flags)] = WinFunctionType 134 return WinFunctionType 135 if WINFUNCTYPE.__doc__: 136 WINFUNCTYPE.__doc__ = CFUNCTYPE.__doc__.replace("CFUNCTYPE", "WINFUNCTYPE") 137 138elif _os.name == "posix": 139 from _ctypes import dlopen as _dlopen 140 141from _ctypes import sizeof, byref, addressof, alignment, resize 142from _ctypes import get_errno, set_errno 143from _ctypes import _SimpleCData 144 145def _check_size(typ, typecode=None): 146 # Check if sizeof(ctypes_type) against struct.calcsize. This 147 # should protect somewhat against a misconfigured libffi. 148 from struct import calcsize 149 if typecode is None: 150 # Most _type_ codes are the same as used in struct 151 typecode = typ._type_ 152 actual, required = sizeof(typ), calcsize(typecode) 153 if actual != required: 154 raise SystemError("sizeof(%s) wrong: %d instead of %d" % \ 155 (typ, actual, required)) 156 157class py_object(_SimpleCData): 158 _type_ = "O" 159 def __repr__(self): 160 try: 161 return super().__repr__() 162 except ValueError: 163 return "%s(<NULL>)" % type(self).__name__ 164_check_size(py_object, "P") 165 166class c_short(_SimpleCData): 167 _type_ = "h" 168_check_size(c_short) 169 170class c_ushort(_SimpleCData): 171 _type_ = "H" 172_check_size(c_ushort) 173 174class c_long(_SimpleCData): 175 _type_ = "l" 176_check_size(c_long) 177 178class c_ulong(_SimpleCData): 179 _type_ = "L" 180_check_size(c_ulong) 181 182if _calcsize("i") == _calcsize("l"): 183 # if int and long have the same size, make c_int an alias for c_long 184 c_int = c_long 185 c_uint = c_ulong 186else: 187 class c_int(_SimpleCData): 188 _type_ = "i" 189 _check_size(c_int) 190 191 class c_uint(_SimpleCData): 192 _type_ = "I" 193 _check_size(c_uint) 194 195class c_float(_SimpleCData): 196 _type_ = "f" 197_check_size(c_float) 198 199class c_double(_SimpleCData): 200 _type_ = "d" 201_check_size(c_double) 202 203class c_longdouble(_SimpleCData): 204 _type_ = "g" 205if sizeof(c_longdouble) == sizeof(c_double): 206 c_longdouble = c_double 207 208if _calcsize("l") == _calcsize("q"): 209 # if long and long long have the same size, make c_longlong an alias for c_long 210 c_longlong = c_long 211 c_ulonglong = c_ulong 212else: 213 class c_longlong(_SimpleCData): 214 _type_ = "q" 215 _check_size(c_longlong) 216 217 class c_ulonglong(_SimpleCData): 218 _type_ = "Q" 219 ## def from_param(cls, val): 220 ## return ('d', float(val), val) 221 ## from_param = classmethod(from_param) 222 _check_size(c_ulonglong) 223 224class c_ubyte(_SimpleCData): 225 _type_ = "B" 226c_ubyte.__ctype_le__ = c_ubyte.__ctype_be__ = c_ubyte 227# backward compatibility: 228##c_uchar = c_ubyte 229_check_size(c_ubyte) 230 231class c_byte(_SimpleCData): 232 _type_ = "b" 233c_byte.__ctype_le__ = c_byte.__ctype_be__ = c_byte 234_check_size(c_byte) 235 236class c_char(_SimpleCData): 237 _type_ = "c" 238c_char.__ctype_le__ = c_char.__ctype_be__ = c_char 239_check_size(c_char) 240 241class c_char_p(_SimpleCData): 242 _type_ = "z" 243 def __repr__(self): 244 return "%s(%s)" % (self.__class__.__name__, c_void_p.from_buffer(self).value) 245_check_size(c_char_p, "P") 246 247class c_void_p(_SimpleCData): 248 _type_ = "P" 249c_voidp = c_void_p # backwards compatibility (to a bug) 250_check_size(c_void_p) 251 252class c_bool(_SimpleCData): 253 _type_ = "?" 254 255from _ctypes import POINTER, pointer, _pointer_type_cache 256 257class c_wchar_p(_SimpleCData): 258 _type_ = "Z" 259 def __repr__(self): 260 return "%s(%s)" % (self.__class__.__name__, c_void_p.from_buffer(self).value) 261 262class c_wchar(_SimpleCData): 263 _type_ = "u" 264 265def _reset_cache(): 266 _pointer_type_cache.clear() 267 _c_functype_cache.clear() 268 if _os.name == "nt": 269 _win_functype_cache.clear() 270 # _SimpleCData.c_wchar_p_from_param 271 POINTER(c_wchar).from_param = c_wchar_p.from_param 272 # _SimpleCData.c_char_p_from_param 273 POINTER(c_char).from_param = c_char_p.from_param 274 _pointer_type_cache[None] = c_void_p 275 276def create_unicode_buffer(init, size=None): 277 """create_unicode_buffer(aString) -> character array 278 create_unicode_buffer(anInteger) -> character array 279 create_unicode_buffer(aString, anInteger) -> character array 280 """ 281 if isinstance(init, str): 282 if size is None: 283 if sizeof(c_wchar) == 2: 284 # UTF-16 requires a surrogate pair (2 wchar_t) for non-BMP 285 # characters (outside [U+0000; U+FFFF] range). +1 for trailing 286 # NUL character. 287 size = sum(2 if ord(c) > 0xFFFF else 1 for c in init) + 1 288 else: 289 # 32-bit wchar_t (1 wchar_t per Unicode character). +1 for 290 # trailing NUL character. 291 size = len(init) + 1 292 _sys.audit("ctypes.create_unicode_buffer", init, size) 293 buftype = c_wchar * size 294 buf = buftype() 295 buf.value = init 296 return buf 297 elif isinstance(init, int): 298 _sys.audit("ctypes.create_unicode_buffer", None, init) 299 buftype = c_wchar * init 300 buf = buftype() 301 return buf 302 raise TypeError(init) 303 304 305def SetPointerType(pointer, cls): 306 import warnings 307 warnings._deprecated("ctypes.SetPointerType", remove=(3, 15)) 308 if _pointer_type_cache.get(cls, None) is not None: 309 raise RuntimeError("This type already exists in the cache") 310 if id(pointer) not in _pointer_type_cache: 311 raise RuntimeError("What's this???") 312 pointer.set_type(cls) 313 _pointer_type_cache[cls] = pointer 314 del _pointer_type_cache[id(pointer)] 315 316def ARRAY(typ, len): 317 return typ * len 318 319################################################################ 320 321 322class CDLL(object): 323 """An instance of this class represents a loaded dll/shared 324 library, exporting functions using the standard C calling 325 convention (named 'cdecl' on Windows). 326 327 The exported functions can be accessed as attributes, or by 328 indexing with the function name. Examples: 329 330 <obj>.qsort -> callable object 331 <obj>['qsort'] -> callable object 332 333 Calling the functions releases the Python GIL during the call and 334 reacquires it afterwards. 335 """ 336 _func_flags_ = _FUNCFLAG_CDECL 337 _func_restype_ = c_int 338 # default values for repr 339 _name = '<uninitialized>' 340 _handle = 0 341 _FuncPtr = None 342 343 def __init__(self, name, mode=DEFAULT_MODE, handle=None, 344 use_errno=False, 345 use_last_error=False, 346 winmode=None): 347 if name: 348 name = _os.fspath(name) 349 350 # If the filename that has been provided is an iOS/tvOS/watchOS 351 # .fwork file, dereference the location to the true origin of the 352 # binary. 353 if name.endswith(".fwork"): 354 with open(name) as f: 355 name = _os.path.join( 356 _os.path.dirname(_sys.executable), 357 f.read().strip() 358 ) 359 360 self._name = name 361 flags = self._func_flags_ 362 if use_errno: 363 flags |= _FUNCFLAG_USE_ERRNO 364 if use_last_error: 365 flags |= _FUNCFLAG_USE_LASTERROR 366 if _sys.platform.startswith("aix"): 367 """When the name contains ".a(" and ends with ")", 368 e.g., "libFOO.a(libFOO.so)" - this is taken to be an 369 archive(member) syntax for dlopen(), and the mode is adjusted. 370 Otherwise, name is presented to dlopen() as a file argument. 371 """ 372 if name and name.endswith(")") and ".a(" in name: 373 mode |= ( _os.RTLD_MEMBER | _os.RTLD_NOW ) 374 if _os.name == "nt": 375 if winmode is not None: 376 mode = winmode 377 else: 378 import nt 379 mode = nt._LOAD_LIBRARY_SEARCH_DEFAULT_DIRS 380 if '/' in name or '\\' in name: 381 self._name = nt._getfullpathname(self._name) 382 mode |= nt._LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR 383 384 class _FuncPtr(_CFuncPtr): 385 _flags_ = flags 386 _restype_ = self._func_restype_ 387 self._FuncPtr = _FuncPtr 388 389 if handle is None: 390 self._handle = _dlopen(self._name, mode) 391 else: 392 self._handle = handle 393 394 def __repr__(self): 395 return "<%s '%s', handle %x at %#x>" % \ 396 (self.__class__.__name__, self._name, 397 (self._handle & (_sys.maxsize*2 + 1)), 398 id(self) & (_sys.maxsize*2 + 1)) 399 400 def __getattr__(self, name): 401 if name.startswith('__') and name.endswith('__'): 402 raise AttributeError(name) 403 func = self.__getitem__(name) 404 setattr(self, name, func) 405 return func 406 407 def __getitem__(self, name_or_ordinal): 408 func = self._FuncPtr((name_or_ordinal, self)) 409 if not isinstance(name_or_ordinal, int): 410 func.__name__ = name_or_ordinal 411 return func 412 413class PyDLL(CDLL): 414 """This class represents the Python library itself. It allows 415 accessing Python API functions. The GIL is not released, and 416 Python exceptions are handled correctly. 417 """ 418 _func_flags_ = _FUNCFLAG_CDECL | _FUNCFLAG_PYTHONAPI 419 420if _os.name == "nt": 421 422 class WinDLL(CDLL): 423 """This class represents a dll exporting functions using the 424 Windows stdcall calling convention. 425 """ 426 _func_flags_ = _FUNCFLAG_STDCALL 427 428 # XXX Hm, what about HRESULT as normal parameter? 429 # Mustn't it derive from c_long then? 430 from _ctypes import _check_HRESULT, _SimpleCData 431 class HRESULT(_SimpleCData): 432 _type_ = "l" 433 # _check_retval_ is called with the function's result when it 434 # is used as restype. It checks for the FAILED bit, and 435 # raises an OSError if it is set. 436 # 437 # The _check_retval_ method is implemented in C, so that the 438 # method definition itself is not included in the traceback 439 # when it raises an error - that is what we want (and Python 440 # doesn't have a way to raise an exception in the caller's 441 # frame). 442 _check_retval_ = _check_HRESULT 443 444 class OleDLL(CDLL): 445 """This class represents a dll exporting functions using the 446 Windows stdcall calling convention, and returning HRESULT. 447 HRESULT error values are automatically raised as OSError 448 exceptions. 449 """ 450 _func_flags_ = _FUNCFLAG_STDCALL 451 _func_restype_ = HRESULT 452 453class LibraryLoader(object): 454 def __init__(self, dlltype): 455 self._dlltype = dlltype 456 457 def __getattr__(self, name): 458 if name[0] == '_': 459 raise AttributeError(name) 460 try: 461 dll = self._dlltype(name) 462 except OSError: 463 raise AttributeError(name) 464 setattr(self, name, dll) 465 return dll 466 467 def __getitem__(self, name): 468 return getattr(self, name) 469 470 def LoadLibrary(self, name): 471 return self._dlltype(name) 472 473 __class_getitem__ = classmethod(_types.GenericAlias) 474 475cdll = LibraryLoader(CDLL) 476pydll = LibraryLoader(PyDLL) 477 478if _os.name == "nt": 479 pythonapi = PyDLL("python dll", None, _sys.dllhandle) 480elif _sys.platform == "android": 481 pythonapi = PyDLL("libpython%d.%d.so" % _sys.version_info[:2]) 482elif _sys.platform == "cygwin": 483 pythonapi = PyDLL("libpython%d.%d.dll" % _sys.version_info[:2]) 484else: 485 pythonapi = PyDLL(None) 486 487 488if _os.name == "nt": 489 windll = LibraryLoader(WinDLL) 490 oledll = LibraryLoader(OleDLL) 491 492 GetLastError = windll.kernel32.GetLastError 493 from _ctypes import get_last_error, set_last_error 494 495 def WinError(code=None, descr=None): 496 if code is None: 497 code = GetLastError() 498 if descr is None: 499 descr = FormatError(code).strip() 500 return OSError(None, descr, None, code) 501 502if sizeof(c_uint) == sizeof(c_void_p): 503 c_size_t = c_uint 504 c_ssize_t = c_int 505elif sizeof(c_ulong) == sizeof(c_void_p): 506 c_size_t = c_ulong 507 c_ssize_t = c_long 508elif sizeof(c_ulonglong) == sizeof(c_void_p): 509 c_size_t = c_ulonglong 510 c_ssize_t = c_longlong 511 512# functions 513 514from _ctypes import _memmove_addr, _memset_addr, _string_at_addr, _cast_addr 515 516## void *memmove(void *, const void *, size_t); 517memmove = CFUNCTYPE(c_void_p, c_void_p, c_void_p, c_size_t)(_memmove_addr) 518 519## void *memset(void *, int, size_t) 520memset = CFUNCTYPE(c_void_p, c_void_p, c_int, c_size_t)(_memset_addr) 521 522def PYFUNCTYPE(restype, *argtypes): 523 class CFunctionType(_CFuncPtr): 524 _argtypes_ = argtypes 525 _restype_ = restype 526 _flags_ = _FUNCFLAG_CDECL | _FUNCFLAG_PYTHONAPI 527 return CFunctionType 528 529_cast = PYFUNCTYPE(py_object, c_void_p, py_object, py_object)(_cast_addr) 530def cast(obj, typ): 531 return _cast(obj, obj, typ) 532 533_string_at = PYFUNCTYPE(py_object, c_void_p, c_int)(_string_at_addr) 534def string_at(ptr, size=-1): 535 """string_at(ptr[, size]) -> string 536 537 Return the byte string at void *ptr.""" 538 return _string_at(ptr, size) 539 540try: 541 from _ctypes import _wstring_at_addr 542except ImportError: 543 pass 544else: 545 _wstring_at = PYFUNCTYPE(py_object, c_void_p, c_int)(_wstring_at_addr) 546 def wstring_at(ptr, size=-1): 547 """wstring_at(ptr[, size]) -> string 548 549 Return the wide-character string at void *ptr.""" 550 return _wstring_at(ptr, size) 551 552 553if _os.name == "nt": # COM stuff 554 def DllGetClassObject(rclsid, riid, ppv): 555 try: 556 ccom = __import__("comtypes.server.inprocserver", globals(), locals(), ['*']) 557 except ImportError: 558 return -2147221231 # CLASS_E_CLASSNOTAVAILABLE 559 else: 560 return ccom.DllGetClassObject(rclsid, riid, ppv) 561 562 def DllCanUnloadNow(): 563 try: 564 ccom = __import__("comtypes.server.inprocserver", globals(), locals(), ['*']) 565 except ImportError: 566 return 0 # S_OK 567 return ccom.DllCanUnloadNow() 568 569from ctypes._endian import BigEndianStructure, LittleEndianStructure 570from ctypes._endian import BigEndianUnion, LittleEndianUnion 571 572# Fill in specifically-sized types 573c_int8 = c_byte 574c_uint8 = c_ubyte 575for kind in [c_short, c_int, c_long, c_longlong]: 576 if sizeof(kind) == 2: c_int16 = kind 577 elif sizeof(kind) == 4: c_int32 = kind 578 elif sizeof(kind) == 8: c_int64 = kind 579for kind in [c_ushort, c_uint, c_ulong, c_ulonglong]: 580 if sizeof(kind) == 2: c_uint16 = kind 581 elif sizeof(kind) == 4: c_uint32 = kind 582 elif sizeof(kind) == 8: c_uint64 = kind 583del(kind) 584 585if SIZEOF_TIME_T == 8: 586 c_time_t = c_int64 587elif SIZEOF_TIME_T == 4: 588 c_time_t = c_int32 589else: 590 raise SystemError(f"Unexpected sizeof(time_t): {SIZEOF_TIME_T=}") 591 592_reset_cache() 593