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            size = len(init)+1
283        buftype = c_wchar * size
284        buf = buftype()
285        buf.value = init
286        return buf
287    elif isinstance(init, int):
288        buftype = c_wchar * init
289        buf = buftype()
290        return buf
291    raise TypeError(init)
292
293
294# XXX Deprecated
295def SetPointerType(pointer, cls):
296    if _pointer_type_cache.get(cls, None) is not None:
297        raise RuntimeError("This type already exists in the cache")
298    if id(pointer) not in _pointer_type_cache:
299        raise RuntimeError("What's this???")
300    pointer.set_type(cls)
301    _pointer_type_cache[cls] = pointer
302    del _pointer_type_cache[id(pointer)]
303
304# XXX Deprecated
305def ARRAY(typ, len):
306    return typ * len
307
308################################################################
309
310
311class CDLL(object):
312    """An instance of this class represents a loaded dll/shared
313    library, exporting functions using the standard C calling
314    convention (named 'cdecl' on Windows).
315
316    The exported functions can be accessed as attributes, or by
317    indexing with the function name.  Examples:
318
319    <obj>.qsort -> callable object
320    <obj>['qsort'] -> callable object
321
322    Calling the functions releases the Python GIL during the call and
323    reacquires it afterwards.
324    """
325    _func_flags_ = _FUNCFLAG_CDECL
326    _func_restype_ = c_int
327    # default values for repr
328    _name = '<uninitialized>'
329    _handle = 0
330    _FuncPtr = None
331
332    def __init__(self, name, mode=DEFAULT_MODE, handle=None,
333                 use_errno=False,
334                 use_last_error=False):
335        self._name = name
336        flags = self._func_flags_
337        if use_errno:
338            flags |= _FUNCFLAG_USE_ERRNO
339        if use_last_error:
340            flags |= _FUNCFLAG_USE_LASTERROR
341
342        class _FuncPtr(_CFuncPtr):
343            _flags_ = flags
344            _restype_ = self._func_restype_
345        self._FuncPtr = _FuncPtr
346
347        if handle is None:
348            self._handle = _dlopen(self._name, mode)
349        else:
350            self._handle = handle
351
352    def __repr__(self):
353        return "<%s '%s', handle %x at %#x>" % \
354               (self.__class__.__name__, self._name,
355                (self._handle & (_sys.maxsize*2 + 1)),
356                id(self) & (_sys.maxsize*2 + 1))
357
358    def __getattr__(self, name):
359        if name.startswith('__') and name.endswith('__'):
360            raise AttributeError(name)
361        func = self.__getitem__(name)
362        setattr(self, name, func)
363        return func
364
365    def __getitem__(self, name_or_ordinal):
366        func = self._FuncPtr((name_or_ordinal, self))
367        if not isinstance(name_or_ordinal, int):
368            func.__name__ = name_or_ordinal
369        return func
370
371class PyDLL(CDLL):
372    """This class represents the Python library itself.  It allows
373    accessing Python API functions.  The GIL is not released, and
374    Python exceptions are handled correctly.
375    """
376    _func_flags_ = _FUNCFLAG_CDECL | _FUNCFLAG_PYTHONAPI
377
378if _os.name == "nt":
379
380    class WinDLL(CDLL):
381        """This class represents a dll exporting functions using the
382        Windows stdcall calling convention.
383        """
384        _func_flags_ = _FUNCFLAG_STDCALL
385
386    # XXX Hm, what about HRESULT as normal parameter?
387    # Mustn't it derive from c_long then?
388    from _ctypes import _check_HRESULT, _SimpleCData
389    class HRESULT(_SimpleCData):
390        _type_ = "l"
391        # _check_retval_ is called with the function's result when it
392        # is used as restype.  It checks for the FAILED bit, and
393        # raises an OSError if it is set.
394        #
395        # The _check_retval_ method is implemented in C, so that the
396        # method definition itself is not included in the traceback
397        # when it raises an error - that is what we want (and Python
398        # doesn't have a way to raise an exception in the caller's
399        # frame).
400        _check_retval_ = _check_HRESULT
401
402    class OleDLL(CDLL):
403        """This class represents a dll exporting functions using the
404        Windows stdcall calling convention, and returning HRESULT.
405        HRESULT error values are automatically raised as OSError
406        exceptions.
407        """
408        _func_flags_ = _FUNCFLAG_STDCALL
409        _func_restype_ = HRESULT
410
411class LibraryLoader(object):
412    def __init__(self, dlltype):
413        self._dlltype = dlltype
414
415    def __getattr__(self, name):
416        if name[0] == '_':
417            raise AttributeError(name)
418        dll = self._dlltype(name)
419        setattr(self, name, dll)
420        return dll
421
422    def __getitem__(self, name):
423        return getattr(self, name)
424
425    def LoadLibrary(self, name):
426        return self._dlltype(name)
427
428cdll = LibraryLoader(CDLL)
429pydll = LibraryLoader(PyDLL)
430
431if _os.name == "nt":
432    pythonapi = PyDLL("python dll", None, _sys.dllhandle)
433elif _sys.platform == "cygwin":
434    pythonapi = PyDLL("libpython%d.%d.dll" % _sys.version_info[:2])
435else:
436    pythonapi = PyDLL(None)
437
438
439if _os.name == "nt":
440    windll = LibraryLoader(WinDLL)
441    oledll = LibraryLoader(OleDLL)
442
443    if _os.name == "nt":
444        GetLastError = windll.kernel32.GetLastError
445    else:
446        GetLastError = windll.coredll.GetLastError
447    from _ctypes import get_last_error, set_last_error
448
449    def WinError(code=None, descr=None):
450        if code is None:
451            code = GetLastError()
452        if descr is None:
453            descr = FormatError(code).strip()
454        return OSError(None, descr, None, code)
455
456if sizeof(c_uint) == sizeof(c_void_p):
457    c_size_t = c_uint
458    c_ssize_t = c_int
459elif sizeof(c_ulong) == sizeof(c_void_p):
460    c_size_t = c_ulong
461    c_ssize_t = c_long
462elif sizeof(c_ulonglong) == sizeof(c_void_p):
463    c_size_t = c_ulonglong
464    c_ssize_t = c_longlong
465
466# functions
467
468from _ctypes import _memmove_addr, _memset_addr, _string_at_addr, _cast_addr
469
470## void *memmove(void *, const void *, size_t);
471memmove = CFUNCTYPE(c_void_p, c_void_p, c_void_p, c_size_t)(_memmove_addr)
472
473## void *memset(void *, int, size_t)
474memset = CFUNCTYPE(c_void_p, c_void_p, c_int, c_size_t)(_memset_addr)
475
476def PYFUNCTYPE(restype, *argtypes):
477    class CFunctionType(_CFuncPtr):
478        _argtypes_ = argtypes
479        _restype_ = restype
480        _flags_ = _FUNCFLAG_CDECL | _FUNCFLAG_PYTHONAPI
481    return CFunctionType
482
483_cast = PYFUNCTYPE(py_object, c_void_p, py_object, py_object)(_cast_addr)
484def cast(obj, typ):
485    return _cast(obj, obj, typ)
486
487_string_at = PYFUNCTYPE(py_object, c_void_p, c_int)(_string_at_addr)
488def string_at(ptr, size=-1):
489    """string_at(addr[, size]) -> string
490
491    Return the string at addr."""
492    return _string_at(ptr, size)
493
494try:
495    from _ctypes import _wstring_at_addr
496except ImportError:
497    pass
498else:
499    _wstring_at = PYFUNCTYPE(py_object, c_void_p, c_int)(_wstring_at_addr)
500    def wstring_at(ptr, size=-1):
501        """wstring_at(addr[, size]) -> string
502
503        Return the string at addr."""
504        return _wstring_at(ptr, size)
505
506
507if _os.name == "nt": # COM stuff
508    def DllGetClassObject(rclsid, riid, ppv):
509        try:
510            ccom = __import__("comtypes.server.inprocserver", globals(), locals(), ['*'])
511        except ImportError:
512            return -2147221231 # CLASS_E_CLASSNOTAVAILABLE
513        else:
514            return ccom.DllGetClassObject(rclsid, riid, ppv)
515
516    def DllCanUnloadNow():
517        try:
518            ccom = __import__("comtypes.server.inprocserver", globals(), locals(), ['*'])
519        except ImportError:
520            return 0 # S_OK
521        return ccom.DllCanUnloadNow()
522
523from ctypes._endian import BigEndianStructure, LittleEndianStructure
524
525# Fill in specifically-sized types
526c_int8 = c_byte
527c_uint8 = c_ubyte
528for kind in [c_short, c_int, c_long, c_longlong]:
529    if sizeof(kind) == 2: c_int16 = kind
530    elif sizeof(kind) == 4: c_int32 = kind
531    elif sizeof(kind) == 8: c_int64 = kind
532for kind in [c_ushort, c_uint, c_ulong, c_ulonglong]:
533    if sizeof(kind) == 2: c_uint16 = kind
534    elif sizeof(kind) == 4: c_uint32 = kind
535    elif sizeof(kind) == 8: c_uint64 = kind
536del(kind)
537
538_reset_cache()
539