def nsData2bytes(ns, dflt=b''):  # XXX an NSData method?
    '''Create Python C{bytes} from C{NSData}.

       @param ns: The C{NSData} (L{ObjCInstance}).
       @keyword dflt: Default for empty C{NSData} (C{bytes}).

       @return: The bytes (C{bytes}) or I{dflt}.
    '''
    isObjCInstanceOf(ns, NSData, name='ns')
    n = ns.length()
    if n:
        buf = (c_byte * n)()
        ns.getBytes_length_(byref(buf), n)
        return b''.join(iterbytes(buf[:n]))
    return dflt
Exemplo n.º 2
0
def split_encoding(encoding):  # MCCABE 18
    '''Split a type encoding into separate type encodings.

       Does not handle C{bitfield}s, C{array}s, C{struct}s, C{union}s,
       etc. and strips any offset, size or width specifiers from the
       encoding.

       @return: The individual type encodings (C{list}).

       @raise TypeCodeError: Invalid or unbalanced I{encoding}.

       @example:

       >>> split_encoding('^v16@0:8')
       >>> ['^v', '@', ':']

       >>> split_encoding('{CGSize=dd}40@0:8{PyObject=@}Q32')
       >>> ['{CGSize=dd}', '@', ':', '{PyObject=@}', 'Q']

       Supported Type Encodings:

           - B = bool (C++ bool, C99 _Bool)
           - c, C = char, unsigned char
           - f, d = float, double
           - i, I = int, unsigned int
           - l, L = long, unsigned long (32-bit in 64-bit Apps)
           - q, Q = long long, unsigned long long
           - s, S = short, unsigned short
           - t, T = 128-bit int, unsigned int
           - v = void
           - * = string (char *)
           - : = method selector C{SEL/cmd}
           - # = class
           - #"name" = class "name"
           - @ = object instance C{Id/self} or statically typed
           - @"name" = instance C{Id/self} of class "name"
           - ^type = pointer to type
           - ? = unknown type (among other things, used for function pointers)

       PyCocoa specific:

           - P = Python object, shorthand for C{PyObjectEncoding}

       Unsupported Type Encodings:

           - bW = bitfield of width W
           - [Ltype] = array of L items of type
           - E{lb}name=type...E{rb} = structure
           - (name=type...) = union
           - <...> = block
           - ?<...> = block with signature

       Unknown or for ObjC internal use:

           - A = ?
           - j = ?
           - n, N = in, inout
           - o, O = out, bycopy
           - r, R = const, byref
           - V = oneway

       @note: Type encodings may be preceeded by C{"name"}, for example a
              C{bitfield} C{"name"b1}, C{struct} items C{E{lb}CGsize="width"d"heigth"dE{rb}},
              C{union} items, etc. and all such C{"name"} prefixes are ignored.

       @see: U{Type Encodings<https://Developer.Apple.com/library/content/documentation/
             Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html>},
             U{NSHipster Type Encodings<https://NSHipster.com/type-encodings>} and
             U{Digits in type encoding<https://StackOverflow.com/questions/11527385/
             how-are-the-digits-in-objc-method-type-encoding-calculated>}.
    '''
    code   = []
    codes  = []
    opened = []     # opened braces, brackets, parensm etc.
    quoted = False  # inside double quotes

    for b in iterbytes(str2bytes(encoding)):

        if b in _TYPEOPENERS:
            if code and code[-1] != b'^' and not opened:
                codes.append(_join(code))
                code = []
            opened.append(_TYPE2CLOSER[b])
            code.append(b)

        elif b in _TYPECLOSERS:
            code.append(b)
            if not opened or b != opened.pop():
                raise TypeCodeError('encoding %s: %r' % ('unbalanced',
                                    bytes2str(_join(code))))
            if not opened:
                codes.append(_join(code))
                code = []

        elif opened:  # inside braces, etc
            # XXX ignore digits?
            code.append(b)  # stick anything on

        elif b == b'"':
            code.append(b)
            if quoted:  # closing quotes
                code = _join(code)
                if code[:2] in (b'@"', b'#"'):
                    # XXX only @"..." and #"..." are OK
                    # XXX what about ^@"..." and ^#"..."?
                    codes.append(code)
                elif code[:1] == b'"':
                    pass  # ignore prefix "name"
                else:
                    raise TypeCodeError('encoding %s: %r' % ('invalid',
                                        bytes2str(code)))
                code = []
            quoted = not quoted

        elif quoted:  # inside quotes
            # XXX only alphanumeric, '_', '.'?
            code.append(b)  # stick anything on

        elif b in _TYPECODESET:
            if code and code[-1] != b'^':
                # not a pointer, previous char != '^'
                codes.append(_join(code))
                code = []
            code.append(b)

        elif b in _TYPESKIPPED:
            pass  # ignore type, width and offsets

    if opened:
        raise TypeCodeError('encoding %s: %r' % ('unbalanced', bytes2str(encoding)))

    if code:  # final type code
        codes.append(_join(code))
    return codes
Exemplo n.º 3
0
       @example:

       >>> split_emcoding2('v*')
       >>> (['v', '@', ':', '*'], 'v@:*')
    '''
    codes = split_encoding(encoding)
    if codes[1:3] != [b'@', b':']:
        # Add codes for hidden arguments
        codes.insert(1, b'@')  # Id/self type encoding
        codes.insert(2, b':')  # SEL/cmd type encoding

    return codes[start:], _join(codes)


_TYPECODESET = set(iterbytes(b'cCiIsSlLqQfdBvP*@#:b^?'))  # _emcoding2ctype.keys()
_TYPESKIPPED = set(iterbytes(b'0123456789 nNoOrRV'))  # type, width and offsets

_TYPE2CLOSER = {b'{': b'}', b'[': b']', b'(': b')', b'<': b'>'}
_TYPE2OPENER = dict(reversed(_) for _ in _TYPE2CLOSER.items())

_TYPEOPENERS = set(_TYPE2CLOSER.keys())
_TYPECLOSERS = set(_TYPE2CLOSER.values())


def split_encoding(encoding):  # MCCABE 18
    '''Split a type encoding into separate type encodings.

       Does not handle C{bitfield}s, C{array}s, C{struct}s, C{union}s,
       etc. and strips any offset, size or width specifiers from the
       encoding.