1
0
mirror of synced 2025-01-18 22:24:04 +01:00

Some type hint fixes for protocol necessary to compile with mypyc.

This commit is contained in:
Jennifer Taylor 2021-05-31 18:08:31 +00:00
parent 48405f00c5
commit 4a1579b099
6 changed files with 94 additions and 61 deletions

View File

@ -126,7 +126,7 @@ class DXTBuffer:
pixel_color = (0, 0, 0, alpha)
# While not surpassing the image dimensions, assign pixels the colors.
if (x + i) < self.width and (y + j) < self.height:
if pixel_color is not None and (x + i) < self.width and (y + j) < self.height:
self.decompressed_buffer[(y + j) * self.width + (x + i)] = (
struct.pack('<BBBB', *pixel_color)
)

View File

@ -51,7 +51,7 @@ class PackedOrdering:
size - Number of bytes to work with as an integer
allow_expansion - Boolean describing whether to add to the end of the order when needed
"""
self.order: List[int] = []
self.order: List[Optional[int]] = []
self.expand = allow_expansion
for i in range(size):
@ -269,6 +269,8 @@ class BinaryDecoder:
A string representing the name in ascii
"""
length = self.stream.read_int()
if length is None:
raise BinaryEncodingException("Ran out of data when attempting to read node name length!")
binary_length = int(((length * 6) + 7) / 8)
def int_to_bin(integer: int) -> str:
@ -280,7 +282,10 @@ class BinaryDecoder:
data = ''
for i in range(binary_length):
data = data + int_to_bin(self.stream.read_int())
next_byte = self.stream.read_int()
if next_byte is None:
raise BinaryEncodingException("Ran out of data when attempting to read node name!")
data = data + int_to_bin(next_byte)
data_str = [data[i:(i + 6)] for i in range(0, len(data), 6)]
data_int = [int(val, 2) for val in data_str]
ret = ''.join([Node.NODE_NAME_CHARS[val] for val in data_int])
@ -301,6 +306,8 @@ class BinaryDecoder:
while True:
child_type = self.stream.read_int()
if child_type is None:
raise BinaryEncodingException("Ran out of data when attempting to read node type!")
if child_type == Node.END_OF_NODE:
return node
@ -320,13 +327,18 @@ class BinaryDecoder:
Node object
"""
if self.executed:
raise Exception("Logic error, should only call this once per instance")
raise BinaryEncodingException("Logic error, should only call this once per instance")
self.executed = True
# Read the header first
header_length = self.stream.read_int(4)
if header_length is None:
raise BinaryEncodingException("Ran out of data when attempting to read header length!")
root = self.__read_node(self.stream.read_int())
node_type = self.stream.read_int()
if node_type is None:
raise BinaryEncodingException("Ran out of data when attempting to read root node type!")
root = self.__read_node(node_type)
eod = self.stream.read_int()
if eod != Node.END_OF_DOCUMENT:
@ -378,6 +390,8 @@ class BinaryDecoder:
loc = ordering.get_next_short()
elif alignment == 4:
loc = ordering.get_next_int()
if loc is None:
raise BinaryEncodingException("Ran out of data when attempting to read node data location!")
if size is None:
# The size should be read from the first 4 bytes
@ -419,6 +433,8 @@ class BinaryDecoder:
else:
# Array value
loc = ordering.get_next_int()
if loc is None:
raise BinaryEncodingException("Ran out of data when attempting to read array length location!")
# The raw size in bytes
length = struct.unpack('>I', body[loc:(loc + 4)])[0]
@ -602,6 +618,8 @@ class BinaryEncoder:
loc = ordering.get_next_short()
elif alignment == 4:
loc = ordering.get_next_int()
if loc is None:
raise BinaryEncodingException("Ran out of data when attempting to allocate node location!")
if dtype == 'str':
# Need to convert this to encoding from standard string.
@ -633,6 +651,9 @@ class BinaryEncoder:
continue
elif composite:
# Array, but not, somewhat silly
if size is None:
raise Exception("Logic error, node size not set yet this is not an attribute!")
encode_value = f'>{enc}'
self.__add_data(struct.pack(encode_value, *val), size, loc)
ordering.mark_used(size, loc)
@ -643,12 +664,19 @@ class BinaryEncoder:
val = 1 if val else 0
# The size is built-in, emit it
if size is None:
raise Exception("Logic error, node size not set yet this is not an attribute!")
encode_value = f'>{enc}'
self.__add_data(struct.pack(encode_value, val), size, loc)
ordering.mark_used(size, loc)
else:
# Array value
loc = ordering.get_next_int()
if loc is None:
raise BinaryEncodingException("Ran out of data when attempting allocate array location!")
if size is None:
raise Exception("Logic error, node size not set yet this is not an attribute!")
# The raw size in bytes
elems = len(val)

View File

@ -634,7 +634,7 @@ class Node:
Returns:
A string data type name. This string can be fed to typename_to_type to get the original type back.
"""
if self.__type is None:
if self.__translated_type is None:
raise Exception('Logic error, tried to fetch data type before setting type!')
return self.__translated_type['name']
@ -647,7 +647,7 @@ class Node:
Returns:
An integer data length, or None if this node's element has variable length.
"""
if self.__type is None:
if self.__translated_type is None:
raise Exception('Logic error, tried to fetch data length before setting type!')
if self.__translated_type['name'] in {'bin', 'str'}:
return None
@ -661,7 +661,7 @@ class Node:
Returns:
A character that can be passed to struct.pack or struct.unpack.
"""
if self.__type is None:
if self.__translated_type is None:
raise Exception('Logic error, tried to fetch data encoding before setting type!')
return self.__translated_type['enc']
@ -781,6 +781,8 @@ class Node:
Returns:
True if this Node is a composite type, False otherwise.
"""
if self.__translated_type is None:
raise Exception('Logic error, tried to fetch composite determination before setting type!')
return self.__translated_type['composite']
def set_value(self, val: Any) -> None:
@ -793,18 +795,22 @@ class Node:
"""
is_array = isinstance(val, (list, tuple))
if self.__translated_type is None:
raise Exception('Logic error, tried to set value before setting type!')
translated_type: Dict[str, Any] = self.__translated_type
# Handle composite types
if self.__translated_type['composite']:
if translated_type['composite']:
if not is_array:
raise NodeException('Input is not array, expected array')
if len(val) != len(self.__translated_type['enc']):
raise NodeException(f'Input array for {self.__translated_type["name"]} expected to be {len(self.__translated_type["enc"])} elements!')
if len(val) != len(translated_type['enc']):
raise NodeException(f'Input array for {translated_type["name"]} expected to be {len(translated_type["enc"])} elements!')
is_array = False
if is_array != self.__array:
raise NodeException(f'Input {"is" if is_array else "is not"} array, expected {"array" if self.__array else "scalar"}')
def val_to_str(val: Any) -> Union[str, bytes]:
if self.__translated_type['name'] == 'bool':
if translated_type['name'] == 'bool':
# Support user-built boolean types
if val is True:
return 'true'
@ -813,9 +819,9 @@ class Node:
# Support construction from binary
return 'true' if val != 0 else 'false'
elif self.__translated_type['name'] == 'float':
elif translated_type['name'] == 'float':
return str(val)
elif self.__translated_type['name'] == 'ip4':
elif translated_type['name'] == 'ip4':
try:
# Support construction from binary
ip = struct.unpack('BBBB', val)
@ -827,13 +833,13 @@ class Node:
return val
raise NodeException(f'Invalid value {val} for IP4 type')
elif self.__translated_type['int']:
elif translated_type['int']:
return str(val)
else:
# This could return either a string or bytes.
return val
if is_array or self.__translated_type['composite']:
if is_array or translated_type['composite']:
self.__value = [val_to_str(v) for v in val]
else:
self.__value = val_to_str(val)
@ -846,23 +852,27 @@ class Node:
Returns:
A mixed value corresponding to this node's value. The returned value will be of the correct data type.
"""
if self.__translated_type is None:
raise Exception('Logic error, tried to get value before setting type!')
translated_type: Dict[str, Any] = self.__translated_type
def str_to_val(string: Union[str, bytes]) -> Any:
if self.__translated_type['name'] == 'bool':
if translated_type['name'] == 'bool':
return True if string == 'true' else False
elif self.__translated_type['name'] == 'float':
elif translated_type['name'] == 'float':
return float(string)
elif self.__translated_type['name'] == 'ip4':
elif translated_type['name'] == 'ip4':
if not isinstance(string, str):
raise Exception('Logic error, expected a string!')
ip = [int(tup) for tup in string.split('.')]
return struct.pack('BBBB', ip[0], ip[1], ip[2], ip[3])
elif self.__translated_type['int']:
elif translated_type['int']:
return int(string)
else:
# At this point, we could be a string or bytes.
return string
if self.__array or self.__translated_type['composite']:
if self.__array or translated_type['composite']:
return [str_to_val(v) for v in self.__value]
else:
return str_to_val(self.__value)
@ -878,6 +888,10 @@ class Node:
Returns:
A string representing the XML-like data for this node and all children.
"""
if self.__translated_type is None:
raise Exception('Logic error, tried to get XML representation before setting type!')
translated_type: Dict[str, Any] = self.__translated_type
attrs_dict = copy.deepcopy(self.__attrs)
order = sorted(attrs_dict.keys())
if self.data_length != 0:
@ -888,7 +902,7 @@ class Node:
else:
attrs_dict['__count'] = str(len(self.__value))
order.insert(0, '__count')
attrs_dict['__type'] = self.__translated_type['name']
attrs_dict['__type'] = translated_type['name']
order.insert(0, '__type')
def escape(val: Any, attr: bool=False) -> str:
@ -912,14 +926,14 @@ class Node:
attrs = ''
def get_val() -> str:
if self.__array or self.__translated_type['composite']:
if self.__array or translated_type['composite']:
if self.__value is None:
vals = ''
else:
vals = ' '.join([val for val in self.__value])
elif self.__translated_type['name'] == 'str':
elif translated_type['name'] == 'str':
vals = escape(self.__value)
elif self.__translated_type['name'] == 'bin':
elif translated_type['name'] == 'bin':
# Convert to a hex string
def bin_to_hex(binary: int) -> str:
val = hex(binary)[2:]

View File

@ -66,7 +66,7 @@ class EAmuseProtocol:
return bytes(out)
def __decrypt(self, encryption_key: str, data: bytes) -> bytes:
def __decrypt(self, encryption_key: Optional[str], data: bytes) -> bytes:
"""
Given data and an optional encryption key, decrypt the data.
@ -82,6 +82,7 @@ class EAmuseProtocol:
if data is None:
return None
key: Optional[bytes] = None
if encryption_key:
# Key is concatenated with the shared secret above
version, first, second = encryption_key.split('-')
@ -91,8 +92,6 @@ class EAmuseProtocol:
m = hashlib.md5()
m.update(key)
key = m.digest()
else:
key = None
if key:
# This is an encrypted old-style packet
@ -101,7 +100,7 @@ class EAmuseProtocol:
# No encryption
return data
def __encrypt(self, encryption_key: str, data: bytes) -> bytes:
def __encrypt(self, encryption_key: Optional[str], data: bytes) -> bytes:
"""
Given data and an optional encryption key, encrypt the data.
@ -117,7 +116,7 @@ class EAmuseProtocol:
# RC4 is symmetric
return self.__decrypt(encryption_key, data)
def __decompress(self, compression: str, data: bytes) -> bytes:
def __decompress(self, compression: Optional[str], data: bytes) -> bytes:
"""
Given data and an optional compression scheme, decompress the data.
@ -133,21 +132,17 @@ class EAmuseProtocol:
if data is None:
return None
if compression:
if compression is None or compression == 'none':
# This isn't compressed
return data
elif compression == 'lz77':
# This is a compressed new-style packet
lz = Lz77()
return lz.decompress(data)
else:
raise EAmuseException(f'Unknown compression {compression}')
if compression is None or compression == 'none':
# This isn't compressed
return data
elif compression == 'lz77':
# This is a compressed new-style packet
lz = Lz77()
return lz.decompress(data)
else:
raise EAmuseException(f'Unknown compression {compression}')
# No compression
return data
def __compress(self, compression: str, data: bytes) -> bytes:
def __compress(self, compression: Optional[str], data: bytes) -> bytes:
"""
Given data and an optional compression scheme, compress the data.
@ -163,19 +158,15 @@ class EAmuseProtocol:
if data is None:
return None
if compression:
if compression is None or compression == 'none':
# This isn't compressed
return data
elif compression == 'lz77':
# This is a compressed new-style packet
lz = Lz77()
return lz.compress(data)
else:
raise EAmuseException(f'Unknown compression {compression}')
# No compression
return data
if compression is None or compression == 'none':
# This isn't compressed
return data
elif compression == 'lz77':
# This is a compressed new-style packet
lz = Lz77()
return lz.compress(data)
else:
raise EAmuseException(f'Unknown compression {compression}')
def __decode(self, data: bytes) -> Node:
"""

View File

@ -48,7 +48,7 @@ class InputStream:
return bytedata
return None
def read_byte(self) -> bytes:
def read_byte(self) -> Optional[bytes]:
"""
Grab the next byte at the current position. If no byte is available,
return None.
@ -58,7 +58,7 @@ class InputStream:
"""
return self.read_blob(1)
def read_int(self, size: int=1, is_unsigned: bool=True) -> int:
def read_int(self, size: int=1, is_unsigned: bool=True) -> Optional[int]:
"""
Grab the next integer of size 'size' at the current position. If not enough
bytes are available to decode this integer, return None.

View File

@ -69,7 +69,7 @@ class XmlDecoder:
# Skip these, handled
continue
else:
node.set_attribute(attr, attributes.get(attr))
node.set_attribute(attr, attributes[attr])
self.current.append(node)
@ -298,7 +298,7 @@ class XmlDecoder:
if empty:
self.__end_element(tag)
def get_tree(self) -> Node:
def get_tree(self) -> Optional[Node]:
"""
Walk the XML document and parse into nodes.