Exemplo n.º 1
0
def pack(fmt, *values):
    tfmt, fmt = __get_type(fmt)
    if not fmt:
        return ()
    if tfmt != '.':
        raise ValueError('Only variable-length encoding is currently supported')
    result = empty_pack
    i = 0
    for offset, havesize, size, f, val in __pack_iter_fmt(fmt, values):
        if f == 'x':
            if not havesize:
                result += x00
            else:
                result += x00 * size
            # Note: no value, don't increment i
        elif f in 'SsUu':
            if f == 'S' and '\0' in val:
                l = val.find('\0')
            else:
                l = len(val)
            if havesize or f == 's':
                if l > size:
                    l = size
            elif (f == 'u' and offset != len(fmt) - 1) or f == 'U':
                result += pack_int(l)
            if _is_string(val) and f in 'Ss':
                result += str(val[:l]).encode()
            else:
                result += val[:l].encode()
            if f == 'S' and not havesize:
                result += x00
            elif size > l and havesize:
                result += x00 * (size - l)
        elif f in 't':
            # bit type, size is number of bits
            if not havesize:
                size = 1
            if size > 8:
                raise ValueError("bit count cannot be greater than 8 for 't' encoding")
            mask = (1 << size) - 1
            if (mask & val) != val:
                raise ValueError("value out of range for 't' encoding")
            result += _chr(val)
        elif f in 'Bb':
            # byte type
            if not havesize:
                size = 1
            for i in range(size):
                if f == 'B':
                    v = val
                else:
                    # Translate to maintain ordering with the sign bit.
                    v = val + 0x80
                if v > 255 or v < 0:
                    raise ValueError("value out of range for 'B' encoding")
                result += _chr(v)
        else:
            # integral type
            result += pack_int(val)
    return result
Exemplo n.º 2
0
def pack_int(x):
    if x < NEG_2BYTE_MIN:
        packed = struct.pack('>Q', x & UINT64_MASK)
        while packed and packed[0] == xff_entry:
            packed = packed[1:]
        return _chr(NEG_MULTI_MARKER | getbits(8 - len(packed), 4)) + packed
    elif x < NEG_1BYTE_MIN:
        x -= NEG_2BYTE_MIN
        return _chr(NEG_2BYTE_MARKER | getbits(x, 13, 8), getbits(x, 8))
    elif x < 0:
        x -= NEG_1BYTE_MIN
        return _chr(NEG_1BYTE_MARKER | getbits(x, 6))
    elif x <= POS_1BYTE_MAX:
        return _chr(POS_1BYTE_MARKER | getbits(x, 6))
    elif x <= POS_2BYTE_MAX:
        x -= (POS_1BYTE_MAX + 1)
        return _chr(POS_2BYTE_MARKER | getbits(x, 13, 8), getbits(x, 8))
    elif x == POS_2BYTE_MAX + 1:
        # This is a special case where we could store the value with
        # just a single byte, but we append a zero byte so that the
        # encoding doesn't get shorter for this one value.
        return _chr(POS_MULTI_MARKER | 0x1, 0)
    else:
        packed = struct.pack('>Q', x - (POS_2BYTE_MAX + 1))
        while packed and packed[0] == x00_entry:
            packed = packed[1:]
        return _chr(POS_MULTI_MARKER | getbits(len(packed), 4)) + packed