More cleanup, merged pymumble into the project so I don't have to maintain 2 separate things, tested working version.
This commit is contained in:
128
pymumble_py3/tools.py
Normal file
128
pymumble_py3/tools.py
Normal file
@@ -0,0 +1,128 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import struct
|
||||
|
||||
|
||||
class InvalidVarInt(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class VarInt:
|
||||
"""Implement the varint type used in mumble"""
|
||||
def __init__(self, value=0):
|
||||
self.value = value
|
||||
|
||||
def encode(self):
|
||||
"""Encode an integer in the VarInt format, returning a binary string"""
|
||||
result = bytearray()
|
||||
value = abs(self.value)
|
||||
|
||||
if self.value < 0:
|
||||
if self.value >= -3:
|
||||
return struct.pack("!B", (0b11111100 | value))
|
||||
else:
|
||||
result = struct.pack("!B", 0b11111000)
|
||||
|
||||
if value <= 0x7f:
|
||||
return result + struct.pack("!B", value)
|
||||
elif value <= 0x3fff:
|
||||
return result + struct.pack("!H", 0x8000 | value)
|
||||
elif value <= 0x1fffff:
|
||||
return result + struct.pack("!BH", 0xc0 | (value >> 16), 0xffff & value)
|
||||
elif value <= 0xfffffff:
|
||||
return result + struct.pack("!L", 0xe0000000 | value)
|
||||
elif value <= 0xffffffff:
|
||||
return result + struct.pack("!BL", 0b11110000, value)
|
||||
else:
|
||||
return result + struct.pack("!BQ", 0b11110100, value)
|
||||
|
||||
def decode(self, value):
|
||||
"""Decode a VarInt contained in a binary string, returning an integer"""
|
||||
varint = value
|
||||
is_negative = False
|
||||
result = None
|
||||
size = 0
|
||||
|
||||
if len(varint) <= 0:
|
||||
raise InvalidVarInt("length can't be 0")
|
||||
|
||||
(first, ) = struct.unpack("!B", varint[0:1])
|
||||
|
||||
if first & 0b11111100 == 0b11111000:
|
||||
is_negative = True
|
||||
size += 1
|
||||
if len(varint) < 2:
|
||||
raise InvalidVarInt("Too short negative varint")
|
||||
varint = varint[1:]
|
||||
(first, ) = struct.unpack("!B", varint[0:1])
|
||||
|
||||
if first & 0b10000000 == 0b00000000:
|
||||
(result, ) = struct.unpack("!B", varint[0:1])
|
||||
size += 1
|
||||
elif first & 0b11111100 == 0b11111100:
|
||||
(result, ) = struct.unpack("!B", varint[0:1])
|
||||
result &= 0b00000011
|
||||
is_negative = True
|
||||
size += 1
|
||||
elif first & 0b11000000 == 0b10000000:
|
||||
if len(varint) < 2:
|
||||
raise InvalidVarInt("Too short 2 bytes varint")
|
||||
(result, ) = struct.unpack("!H", varint[:2])
|
||||
result &= 0b0011111111111111
|
||||
size += 2
|
||||
elif first & 0b11100000 == 0b11000000:
|
||||
if len(varint) < 3:
|
||||
raise InvalidVarInt("Too short 3 bytes varint")
|
||||
(result, ) = struct.unpack("!B", varint[0:1])
|
||||
result &= 0b00011111
|
||||
(tmp, ) = struct.unpack("!H", varint[1:3])
|
||||
result = (result << 16) + tmp
|
||||
size += 3
|
||||
elif first & 0b11110000 == 0b11100000:
|
||||
if len(varint) < 4:
|
||||
raise InvalidVarInt("Too short 4 bytes varint")
|
||||
(result, ) = struct.unpack("!L", varint[:4])
|
||||
result &= 0x0fffffff
|
||||
size += 4
|
||||
elif first & 0b11111100 == 0b11110000:
|
||||
if len(varint) < 5:
|
||||
raise InvalidVarInt("Too short 5 bytes varint")
|
||||
(result, ) = struct.unpack("!L", varint[1:5])
|
||||
size += 5
|
||||
elif first & 0b11111100 == 0b11110100:
|
||||
if len(varint) < 9:
|
||||
raise InvalidVarInt("Too short 9 bytes varint")
|
||||
(result, ) = struct.unpack("!Q", varint[1:9])
|
||||
size += 9
|
||||
|
||||
if is_negative:
|
||||
self.value = - result
|
||||
else:
|
||||
self.value = result
|
||||
|
||||
return size
|
||||
|
||||
|
||||
def tohex(buffer):
|
||||
"""Used for debugging. Output a sting in hex format"""
|
||||
result = "\n"
|
||||
cpt1 = 0
|
||||
cpt2 = 0
|
||||
|
||||
for byte in buffer:
|
||||
result += hex(ord(byte))[2:].zfill(2)
|
||||
cpt1 += 1
|
||||
|
||||
if cpt1 >= 4:
|
||||
result += " "
|
||||
cpt1 = 0
|
||||
cpt2 += 1
|
||||
|
||||
if cpt2 >= 10:
|
||||
result += "\n"
|
||||
cpt2 = 0
|
||||
|
||||
return result
|
||||
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user