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 in ("nt", "ce"):
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()[2].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"""
38WINOLEAPI -> HRESULT
39WINOLEAPI_(type)
40
41STDMETHODCALLTYPE
42
43STDMETHOD(name)
44STDMETHOD_(type, name)
45
46STDAPICALLTYPE
47"""
48
49def create_string_buffer(init, size=None):
50    """create_string_buffer(aString) -> character array
51    create_string_buffer(anInteger) -> character array
52    create_string_buffer(aString, anInteger) -> character array
53    """
54    if isinstance(init, (str, unicode)):
55        if size is None:
56            size = len(init)+1
57        buftype = c_char * size
58        buf = buftype()
59        buf.value = init
60        return buf
61    elif isinstance(init, (int, long)):
62        buftype = c_char * init
63        buf = buftype()
64        return buf
65    raise TypeError(init)
66
67def c_buffer(init, size=None):
68##    "deprecated, use create_string_buffer instead"
69##    import warnings
70##    warnings.warn("c_buffer is deprecated, use create_string_buffer instead",
71##                  DeprecationWarning, stacklevel=2)
72    return create_string_buffer(init, size)
73
74_c_functype_cache = {}
75def CFUNCTYPE(restype, *argtypes, **kw):
76    """CFUNCTYPE(restype, *argtypes,
77                 use_errno=False, use_last_error=False) -> function prototype.
78
79    restype: the result type
80    argtypes: a sequence specifying the argument types
81
82    The function prototype can be called in different ways to create a
83    callable object:
84
85    prototype(integer address) -> foreign function
86    prototype(callable) -> create and return a C callable function from callable
87    prototype(integer index, method name[, paramflags]) -> foreign function calling a COM method
88    prototype((ordinal number, dll object)[, paramflags]) -> foreign function exported by ordinal
89    prototype((function name, dll object)[, paramflags]) -> foreign function exported by name
90    """
91    flags = _FUNCFLAG_CDECL
92    if kw.pop("use_errno", False):
93        flags |= _FUNCFLAG_USE_ERRNO
94    if kw.pop("use_last_error", False):
95        flags |= _FUNCFLAG_USE_LASTERROR
96    if kw:
97        raise ValueError("unexpected keyword argument(s) %s" % kw.keys())
98    try:
99        return _c_functype_cache[(restype, argtypes, flags)]
100    except KeyError:
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 in ("nt", "ce"):
109    from _ctypes import LoadLibrary as _dlopen
110    from _ctypes import FUNCFLAG_STDCALL as _FUNCFLAG_STDCALL
111    if _os.name == "ce":
112        # 'ce' doesn't have the stdcall calling convention
113        _FUNCFLAG_STDCALL = _FUNCFLAG_CDECL
114
115    _win_functype_cache = {}
116    def WINFUNCTYPE(restype, *argtypes, **kw):
117        # docstring set later (very similar to CFUNCTYPE.__doc__)
118        flags = _FUNCFLAG_STDCALL
119        if kw.pop("use_errno", False):
120            flags |= _FUNCFLAG_USE_ERRNO
121        if kw.pop("use_last_error", False):
122            flags |= _FUNCFLAG_USE_LASTERROR
123        if kw:
124            raise ValueError("unexpected keyword argument(s) %s" % kw.keys())
125        try:
126            return _win_functype_cache[(restype, argtypes, flags)]
127        except KeyError:
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(py_object, self).__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    if _os.name == "nt":
243        def __repr__(self):
244            if not windll.kernel32.IsBadStringPtrA(self, -1):
245                return "%s(%r)" % (self.__class__.__name__, self.value)
246            return "%s(%s)" % (self.__class__.__name__, cast(self, c_void_p).value)
247    else:
248        def __repr__(self):
249            return "%s(%s)" % (self.__class__.__name__, cast(self, c_void_p).value)
250_check_size(c_char_p, "P")
251
252class c_void_p(_SimpleCData):
253    _type_ = "P"
254c_voidp = c_void_p # backwards compatibility (to a bug)
255_check_size(c_void_p)
256
257class c_bool(_SimpleCData):
258    _type_ = "?"
259
260from _ctypes import POINTER, pointer, _pointer_type_cache
261
262def _reset_cache():
263    _pointer_type_cache.clear()
264    _c_functype_cache.clear()
265    if _os.name in ("nt", "ce"):
266        _win_functype_cache.clear()
267    # _SimpleCData.c_wchar_p_from_param
268    POINTER(c_wchar).from_param = c_wchar_p.from_param
269    # _SimpleCData.c_char_p_from_param
270    POINTER(c_char).from_param = c_char_p.from_param
271    _pointer_type_cache[None] = c_void_p
272    # XXX for whatever reasons, creating the first instance of a callback
273    # function is needed for the unittests on Win64 to succeed.  This MAY
274    # be a compiler bug, since the problem occurs only when _ctypes is
275    # compiled with the MS SDK compiler.  Or an uninitialized variable?
276    CFUNCTYPE(c_int)(lambda: None)
277
278try:
279    from _ctypes import set_conversion_mode
280except ImportError:
281    pass
282else:
283    if _os.name in ("nt", "ce"):
284        set_conversion_mode("mbcs", "ignore")
285    else:
286        set_conversion_mode("ascii", "strict")
287
288    class c_wchar_p(_SimpleCData):
289        _type_ = "Z"
290
291    class c_wchar(_SimpleCData):
292        _type_ = "u"
293
294    def create_unicode_buffer(init, size=None):
295        """create_unicode_buffer(aString) -> character array
296        create_unicode_buffer(anInteger) -> character array
297        create_unicode_buffer(aString, anInteger) -> character array
298        """
299        if isinstance(init, (str, unicode)):
300            if size is None:
301                size = len(init)+1
302            buftype = c_wchar * size
303            buf = buftype()
304            buf.value = init
305            return buf
306        elif isinstance(init, (int, long)):
307            buftype = c_wchar * init
308            buf = buftype()
309            return buf
310        raise TypeError(init)
311
312# XXX Deprecated
313def SetPointerType(pointer, cls):
314    if _pointer_type_cache.get(cls, None) is not None:
315        raise RuntimeError("This type already exists in the cache")
316    if id(pointer) not in _pointer_type_cache:
317        raise RuntimeError("What's this???")
318    pointer.set_type(cls)
319    _pointer_type_cache[cls] = pointer
320    del _pointer_type_cache[id(pointer)]
321
322# XXX Deprecated
323def ARRAY(typ, len):
324    return typ * len
325
326################################################################
327
328
329class CDLL(object):
330    """An instance of this class represents a loaded dll/shared
331    library, exporting functions using the standard C calling
332    convention (named 'cdecl' on Windows).
333
334    The exported functions can be accessed as attributes, or by
335    indexing with the function name.  Examples:
336
337    <obj>.qsort -> callable object
338    <obj>['qsort'] -> callable object
339
340    Calling the functions releases the Python GIL during the call and
341    reacquires it afterwards.
342    """
343    _func_flags_ = _FUNCFLAG_CDECL
344    _func_restype_ = c_int
345    # default values for repr
346    _name = '<uninitialized>'
347    _handle = 0
348    _FuncPtr = None
349
350    def __init__(self, name, mode=DEFAULT_MODE, handle=None,
351                 use_errno=False,
352                 use_last_error=False):
353        self._name = name
354        flags = self._func_flags_
355        if use_errno:
356            flags |= _FUNCFLAG_USE_ERRNO
357        if use_last_error:
358            flags |= _FUNCFLAG_USE_LASTERROR
359
360        class _FuncPtr(_CFuncPtr):
361            _flags_ = flags
362            _restype_ = self._func_restype_
363        self._FuncPtr = _FuncPtr
364
365        if handle is None:
366            self._handle = _dlopen(self._name, mode)
367        else:
368            self._handle = handle
369
370    def __repr__(self):
371        return "<%s '%s', handle %x at %x>" % \
372               (self.__class__.__name__, self._name,
373                (self._handle & (_sys.maxint*2 + 1)),
374                id(self) & (_sys.maxint*2 + 1))
375
376    def __getattr__(self, name):
377        if name.startswith('__') and name.endswith('__'):
378            raise AttributeError(name)
379        func = self.__getitem__(name)
380        setattr(self, name, func)
381        return func
382
383    def __getitem__(self, name_or_ordinal):
384        func = self._FuncPtr((name_or_ordinal, self))
385        if not isinstance(name_or_ordinal, (int, long)):
386            func.__name__ = name_or_ordinal
387        return func
388
389class PyDLL(CDLL):
390    """This class represents the Python library itself.  It allows
391    accessing Python API functions.  The GIL is not released, and
392    Python exceptions are handled correctly.
393    """
394    _func_flags_ = _FUNCFLAG_CDECL | _FUNCFLAG_PYTHONAPI
395
396if _os.name in ("nt", "ce"):
397
398    class WinDLL(CDLL):
399        """This class represents a dll exporting functions using the
400        Windows stdcall calling convention.
401        """
402        _func_flags_ = _FUNCFLAG_STDCALL
403
404    # XXX Hm, what about HRESULT as normal parameter?
405    # Mustn't it derive from c_long then?
406    from _ctypes import _check_HRESULT, _SimpleCData
407    class HRESULT(_SimpleCData):
408        _type_ = "l"
409        # _check_retval_ is called with the function's result when it
410        # is used as restype.  It checks for the FAILED bit, and
411        # raises a WindowsError if it is set.
412        #
413        # The _check_retval_ method is implemented in C, so that the
414        # method definition itself is not included in the traceback
415        # when it raises an error - that is what we want (and Python
416        # doesn't have a way to raise an exception in the caller's
417        # frame).
418        _check_retval_ = _check_HRESULT
419
420    class OleDLL(CDLL):
421        """This class represents a dll exporting functions using the
422        Windows stdcall calling convention, and returning HRESULT.
423        HRESULT error values are automatically raised as WindowsError
424        exceptions.
425        """
426        _func_flags_ = _FUNCFLAG_STDCALL
427        _func_restype_ = HRESULT
428
429class LibraryLoader(object):
430    def __init__(self, dlltype):
431        self._dlltype = dlltype
432
433    def __getattr__(self, name):
434        if name[0] == '_':
435            raise AttributeError(name)
436        dll = self._dlltype(name)
437        setattr(self, name, dll)
438        return dll
439
440    def __getitem__(self, name):
441        return getattr(self, name)
442
443    def LoadLibrary(self, name):
444        return self._dlltype(name)
445
446cdll = LibraryLoader(CDLL)
447pydll = LibraryLoader(PyDLL)
448
449if _os.name in ("nt", "ce"):
450    pythonapi = PyDLL("python dll", None, _sys.dllhandle)
451elif _sys.platform == "cygwin":
452    pythonapi = PyDLL("libpython%d.%d.dll" % _sys.version_info[:2])
453else:
454    pythonapi = PyDLL(None)
455
456
457if _os.name in ("nt", "ce"):
458    windll = LibraryLoader(WinDLL)
459    oledll = LibraryLoader(OleDLL)
460
461    if _os.name == "nt":
462        GetLastError = windll.kernel32.GetLastError
463    else:
464        GetLastError = windll.coredll.GetLastError
465    from _ctypes import get_last_error, set_last_error
466
467    def WinError(code=None, descr=None):
468        if code is None:
469            code = GetLastError()
470        if descr is None:
471            descr = FormatError(code).strip()
472        return WindowsError(code, descr)
473
474if sizeof(c_uint) == sizeof(c_void_p):
475    c_size_t = c_uint
476    c_ssize_t = c_int
477elif sizeof(c_ulong) == sizeof(c_void_p):
478    c_size_t = c_ulong
479    c_ssize_t = c_long
480elif sizeof(c_ulonglong) == sizeof(c_void_p):
481    c_size_t = c_ulonglong
482    c_ssize_t = c_longlong
483
484# functions
485
486from _ctypes import _memmove_addr, _memset_addr, _string_at_addr, _cast_addr
487
488## void *memmove(void *, const void *, size_t);
489memmove = CFUNCTYPE(c_void_p, c_void_p, c_void_p, c_size_t)(_memmove_addr)
490
491## void *memset(void *, int, size_t)
492memset = CFUNCTYPE(c_void_p, c_void_p, c_int, c_size_t)(_memset_addr)
493
494def PYFUNCTYPE(restype, *argtypes):
495    class CFunctionType(_CFuncPtr):
496        _argtypes_ = argtypes
497        _restype_ = restype
498        _flags_ = _FUNCFLAG_CDECL | _FUNCFLAG_PYTHONAPI
499    return CFunctionType
500
501_cast = PYFUNCTYPE(py_object, c_void_p, py_object, py_object)(_cast_addr)
502def cast(obj, typ):
503    return _cast(obj, obj, typ)
504
505_string_at = PYFUNCTYPE(py_object, c_void_p, c_int)(_string_at_addr)
506def string_at(ptr, size=-1):
507    """string_at(addr[, size]) -> string
508
509    Return the string at addr."""
510    return _string_at(ptr, size)
511
512try:
513    from _ctypes import _wstring_at_addr
514except ImportError:
515    pass
516else:
517    _wstring_at = PYFUNCTYPE(py_object, c_void_p, c_int)(_wstring_at_addr)
518    def wstring_at(ptr, size=-1):
519        """wstring_at(addr[, size]) -> string
520
521        Return the string at addr."""
522        return _wstring_at(ptr, size)
523
524
525if _os.name in ("nt", "ce"): # COM stuff
526    def DllGetClassObject(rclsid, riid, ppv):
527        try:
528            ccom = __import__("comtypes.server.inprocserver", globals(), locals(), ['*'])
529        except ImportError:
530            return -2147221231 # CLASS_E_CLASSNOTAVAILABLE
531        else:
532            return ccom.DllGetClassObject(rclsid, riid, ppv)
533
534    def DllCanUnloadNow():
535        try:
536            ccom = __import__("comtypes.server.inprocserver", globals(), locals(), ['*'])
537        except ImportError:
538            return 0 # S_OK
539        return ccom.DllCanUnloadNow()
540
541from ctypes._endian import BigEndianStructure, LittleEndianStructure
542
543# Fill in specifically-sized types
544c_int8 = c_byte
545c_uint8 = c_ubyte
546for kind in [c_short, c_int, c_long, c_longlong]:
547    if sizeof(kind) == 2: c_int16 = kind
548    elif sizeof(kind) == 4: c_int32 = kind
549    elif sizeof(kind) == 8: c_int64 = kind
550for kind in [c_ushort, c_uint, c_ulong, c_ulonglong]:
551    if sizeof(kind) == 2: c_uint16 = kind
552    elif sizeof(kind) == 4: c_uint32 = kind
553    elif sizeof(kind) == 8: c_uint64 = kind
554del(kind)
555
556_reset_cache()
557