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