(encoding, start)
Find the end index of the encoding starting at index start.
    The encoding is not validated very extensively. There are no guarantees what happens for invalid encodings;
    an error may be raised, or a bogus end index may be returned.
Find the end index of the encoding starting at index start.
    The encoding is not validated very extensively. There are no guarantees what happens for invalid encodings;
    an error may be raised, or a bogus end index may be returned.
Find the end index of the encoding starting at index start . The encoding is not validated very extensively . There are no guarantees what happens for invalid encodings ; an error may be raised or a bogus end index may be returned .
def _end_of_encoding(encoding, start):
    """Find the end index of the encoding starting at index start.
    The encoding is not validated very extensively. There are no guarantees what happens for invalid encodings;
    an error may be raised, or a bogus end index may be returned.
    """

    if start < 0 or start >= len(encoding):
        raise ValueError('Start index {} not in range({})'.format(start, len(encoding)))

    paren_depth = 0

    i = start
    while i < len(encoding):
        c = encoding[i:i+1]
        if c in b'([{<':
            # Opening parenthesis of some type, wait for a corresponding closing paren.
            # This doesn't check that the parenthesis *types* match (only the *number* of closing parens has to match).
            paren_depth += 1
            i += 1
        elif paren_depth > 0:
            if c in b')]}>':
                # Closing parentheses of some type.
                paren_depth -= 1
            i += 1
            if paren_depth == 0:
                # Final closing parenthesis, end of this encoding.
                return i
        elif c in b'*:#?BCDILQSTcdfilqstv':
            # Encodings with exactly one character.
            return i+1
        elif c in b'^ANORVjnor':
            # Simple prefix (qualifier, pointer, etc.), skip it but count it towards the length.
            i += 1
        elif c == b'@':
            if encoding[i+1:i+3] == b'?<':
                # Encoding @?<...> (block with signature).
                # Skip the @? and continue at the < which is treated as an opening paren.
                i += 2
            elif encoding[i+1:i+2] == b'?':
                # Encoding @? (block).
                return i+2
            elif encoding[i+1:i+2] == b'"':
                # Encoding @"..." (object pointer with class name).
                return encoding.index(b'"', i+2)+1
            else:
                # Encoding @ (untyped object pointer).
                return i+1
        elif c == b'b':
            # Bit field, followed by one or more digits.
            for j in range(i+1, len(encoding)):
                if encoding[j] not in b'0123456789':
                    # Found a non-digit, stop here.
                    return j
            # Reached end of string without finding a non-digit, stop.
            return len(encoding)
        else:
            raise ValueError('Unknown encoding {} at index {}: {}'.format(c, i, encoding))

    if paren_depth > 0:
        raise ValueError('Incomplete encoding, missing {} closing parentheses: {}'.format(paren_depth, encoding))
    else:
        raise ValueError('Incomplete encoding, reached end of string too early: {}'.format(encoding))
def _end_of_encoding ( encoding , start ) : if start < 0 or start >= len ( encoding ) : raise ValueError ( 'Start index {} not in range({})' . format ( start , len ( encoding ) ) ) paren_depth = 0 i = start while i < len ( encoding ) : c = encoding [ i : i + 1 ] if c in b'([{<' : # Opening parenthesis of some type, wait for a corresponding closing paren. # This doesn't check that the parenthesis *types* match (only the *number* of closing parens has to match). paren_depth += 1 i += 1 elif paren_depth > 0 : if c in b')]}>' : # Closing parentheses of some type. paren_depth -= 1 i += 1 if paren_depth == 0 : # Final closing parenthesis, end of this encoding. return i elif c in b'*:#?BCDILQSTcdfilqstv' : # Encodings with exactly one character. return i + 1 elif c in b'^ANORVjnor' : # Simple prefix (qualifier, pointer, etc.), skip it but count it towards the length. i += 1 elif c == b'@' : if encoding [ i + 1 : i + 3 ] == b'?<' : # Encoding @?<...> (block with signature). # Skip the @? and continue at the < which is treated as an opening paren. i += 2 elif encoding [ i + 1 : i + 2 ] == b'?' : # Encoding @? (block). return i + 2 elif encoding [ i + 1 : i + 2 ] == b'"' : # Encoding @"..." (object pointer with class name). return encoding . index ( b'"' , i + 2 ) + 1 else : # Encoding @ (untyped object pointer). return i + 1 elif c == b'b' : # Bit field, followed by one or more digits. for j in range ( i + 1 , len ( encoding ) ) : if encoding [ j ] not in b'0123456789' : # Found a non-digit, stop here. return j # Reached end of string without finding a non-digit, stop. return len ( encoding ) else : raise ValueError ( 'Unknown encoding {} at index {}: {}' . format ( c , i , encoding ) ) if paren_depth > 0 : raise ValueError ( 'Incomplete encoding, missing {} closing parentheses: {}' . format ( paren_depth , encoding ) ) else : raise ValueError ( 'Incomplete encoding, reached end of string too early: {}' . format ( encoding ) )