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