osu-repy/osuRepy/helpers/typeSerializer.py

170 lines
3.6 KiB
Python
Raw Normal View History

2019-03-13 09:07:46 +01:00
import struct
2019-03-18 08:00:18 +01:00
TYPE_CHAR = b"b", 1
TYPE_BYTE = b"B", 1
TYPE_BOOL = b"?", 1
TYPE_SHORT = b"h", 2
TYPE_USHORT = b"H", 2
TYPE_INT = b"i", 4
TYPE_UINT = b"I", 4
TYPE_LONG = b"l", 4
TYPE_ULONG = b"L", 4
TYPE_LLONG = b"q", 8
TYPE_ULLONG = b"Q", 8
TYPE_FLOAT = b"f", 4
TYPE_DOUBLE = b"d", 8
TYPE_STRING = b"s", 1
2019-03-19 14:10:14 +01:00
TYPE_ULEB = b"s", 1, True # True just so they are different tuples
2019-03-13 09:07:46 +01:00
BYTEORDER_NATIVE = b"@"
BYTEORDER_LITTLE = b"<"
BYTEORDER_BIG = b">"
2019-03-13 12:59:24 +01:00
def encode_uleb(val):
data = b""
while val != 0:
b = val & 0x7f
val >>= 7
if val != 0:
b |= 0x80
data += bytes([b])
return data
def decode_uleb(data):
val = 0
shift = 0
pos = 0
while True:
b = data[pos]
pos += 1
val |= (b & 0x7f) << shift
if (b & 0x80) == 0:
break
shift += 7
return val, pos
2019-03-13 09:07:46 +01:00
def guess_type(value):
t_value = type(value)
if t_value is bool:
return TYPE_BOOL
if t_value is float:
return TYPE_FLOAT
if t_value is str:
return TYPE_STRING
if t_value is bytes:
return TYPE_STRING
if t_value is int:
bit_len = 0
while value:
value >>= 1
bit_len += 1
byte_len = (bit_len + 1) // 2
if byte_len <= 1:
return TYPE_BYTE
if byte_len <= 2:
return TYPE_USHORT
if byte_len <= 4:
return TYPE_UINT
if byte_len <= 8:
return TYPE_ULLONG
raise Exception("Unable to guess type")
2019-03-18 08:00:18 +01:00
def read(value_type, stream):
#if value_type == TYPE_STRING:
# read()
struct.unpack(value_type[0], stream[:value_type[1]])
2019-03-13 09:07:46 +01:00
class Serializable:
2019-03-19 14:10:14 +01:00
length = None
prefix = b""
filter = None
2019-03-13 09:07:46 +01:00
2019-03-19 14:10:14 +01:00
def __init__(self, value, type = None, length = None, prefix = b"", filter = None):
2019-03-13 09:07:46 +01:00
self.value = value
if type is not None:
self.type = type
else:
self.type = guess_type(type)
2019-03-18 08:00:18 +01:00
self.length = length
self.prefix = prefix
2019-03-19 14:10:14 +01:00
self.filter = filter
2019-03-13 09:07:46 +01:00
2019-03-19 14:10:14 +01:00
def get_struct_fmt(self, length = 1):
struct_fmt = self.type[0]
if length > 1:
struct_fmt = b"%d%b" % (length, self.type[0])
2019-03-18 08:00:18 +01:00
if self.length is not None:
2019-03-19 14:10:14 +01:00
if self.length == TYPE_ULEB:
val = self.get_value()
struct_fmt = b"%d%b%b" % (len(val[0]), self.length[0], struct_fmt)
else:
struct_fmt = b"%b%b" % (self.length[0], struct_fmt)
return struct_fmt
2019-03-13 09:07:46 +01:00
def get_value(self):
2019-03-19 14:10:14 +01:00
val = [self.value]
if self.filter is not None:
val[-1] = self.filter(val[-1])
if self.length is not None:
if self.length == TYPE_ULEB:
val.insert(0, encode_uleb(len(val[-1])))
else:
val.insert(0, len(val[-1]))
2019-03-13 09:07:46 +01:00
return val
def pack(self, byte_order = BYTEORDER_LITTLE):
2019-03-19 14:10:14 +01:00
length = 1
if self.type == TYPE_STRING:
length = len(self.get_value()[-1])
struct_fmt = byte_order + self.get_struct_fmt(length)
packed = struct.pack(struct_fmt, *self.get_value())
2019-03-18 08:00:18 +01:00
if self.prefix is not None:
packed = self.prefix + packed
return packed
def unpack(self, length = -1, byte_order = BYTEORDER_LITTLE):
if self.type == TYPE_STRING:
2019-03-19 14:10:14 +01:00
length = len(self.value)
2019-03-18 08:00:18 +01:00
struct_fmt = byte_order + self.get_struct_fmt(length)
2019-03-13 09:07:46 +01:00
class Serializer:
def __init__(self, byte_order = BYTEORDER_LITTLE):
self.stack = []
self.byte_order = byte_order
def add(self, serializable):
if type(serializable) is list:
self.stack += serializable
else:
self.stack.append(serializable)
def flush(self):
return b"".join(s.pack() for s in self.stack)
def __bytes__(self):
return self.flush()
2019-03-18 08:00:18 +01:00
class Deserializer:
def __init__(self, byte_order = BYTEORDER_LITTLE):
self.stack = []
self.byte_order = byte_order
def add(self, serializable):
if type(serializable) is list:
self.stack += serializable
else:
self.stack.append(serializable)
"""
def deserialize_data(self, stream):
pos = 0
for s in self.stack:
struct.
s.value
"""