See More

from ..streams import EndianBinaryReader class RefInt: v: int def __init__(self, value): self._value = value def __add__(self, other): return self._value + other def __sub__(self, other): self._value -= other return self._value def __int__(self): return self._value def __getattr__(self, item): return self._value def __getitem__(self, item): return self._value def __setattr__(self, key, value): self.__dict__["_value"] = value def __setitem__(self, key, value): self._value = value def __mod__(self, other): return self._value % other def __ge__(self, other): return self._value >= other def __gt__(self, other): return self._value > other def __le__(self, other): return self._value <= other def __lt__(self, other): return self._value < other def __eq__(self, other): return self._value == other def get_members(members: list, level: int, index: int) -> list: member2 = [members[0]] for i in range(index + 1, len(members)): member = members[i] if member.level <= level: return member2 member2.append(member) return member2 class TypeTreeHelper: def __init__(self, reader: EndianBinaryReader): self.reader = reader self.READ = { "SInt8": self.reader.read_byte, "UInt8": self.reader.read_u_byte, "short": self.reader.read_short, "SInt16": self.reader.read_short, "unsigned short": self.reader.read_u_short, "UInt16": self.reader.read_u_short, "int": self.reader.read_int, "SInt32": self.reader.read_int, "unsigned int": self.reader.read_u_int, "UInt32": self.reader.read_u_int, "Type*": self.reader.read_u_int, "long long": self.reader.read_long, "SInt64": self.reader.read_long, "unsigned long long": self.reader.read_u_long, "UInt64": self.reader.read_u_long, "float": self.reader.read_float, "double": self.reader.read_double, "bool": self.reader.read_boolean, } self.READ2 = { "string": self.read_string, "map": self.read_map, "TypelessData": self.read_typeless_data, } def read_u_type(self, members: list) -> dict: i = RefInt(0) obj = {} while i.v < len(members): member = members[i.v] obj[member.name] = self.read_value(members, i) i.v += 1 return obj def read_string(self, i, align, *args): value = self.reader.read_aligned_string() i.v += 3 return value, align def read_map(self, i, align, members, level): if (members[i + 1].meta_flag & 0x4000) != 0: align = True size = self.reader.read_int() map_ = get_members(members, level, i)[4:] i.v += len(map_) + 3 first = get_members(map_, map_[0].level, 0) second = map_[len(first) :] value = {} for j in range(size): tmp1 = RefInt(0) tmp2 = RefInt(0) v1 = self.read_value( first, tmp1 ) # python reads the value first and then the key, so it has to be this way if isinstance(v1, dict): value[first] = tmp1 value["values"] = self.read_value(second, tmp2) else: value[v1] = self.read_value(second, tmp2) return value, align def read_typeless_data(self, i, align, *args): size = self.reader.read_int() value = self.reader.read_bytes(size) i.v += 2 return value, align def read_value(self, members: list, _i) -> object: i = RefInt(_i) if type(_i) != RefInt else _i member = members[i.v] level = member.level var_type_str = member.type align = (member.meta_flag & 0x4000) != 0 value = self.READ.get(var_type_str) if value: value = value() else: value = self.READ2.get(var_type_str) if value: value, align = value(i, align, members, level) else: if i != len(members) and members[i.v + 1].type == "Array": if (members[i.v + 1].meta_flag & 0x4000) != 0: align = True size = self.reader.read_int() vector = get_members(members, level, i)[3:] i.v += len(vector) + 2 value = [self.read_value(vector, 0) for _ in range(size)] else: eclass = get_members(members, level, i) eclass.pop(0) i.v += len(eclass) j = RefInt(0) value = {} while j < len(eclass): classmember = eclass[j.v] name = classmember.name value[name] = self.read_value(eclass, j) j.v += 1 if align: self.reader.align_stream() return value def read_type_string(self, sb: list, members: list): i = RefInt(0) while i < len(members): self.read_string_value(sb, members, i) i.v += 1 return sb def read_string_value(self, sb: list, members, i: RefInt): if type(i) != RefInt: i = RefInt(i) member = members[i.v] level = member.level var_type_str = member.type var_name_str = member.name append = True align = (member.meta_flag & 0x4000) != 0 value = self.READ.get(var_type_str) if value: value = value() elif var_type_str == "string": append = False string = self.reader.read_aligned_string() sb.append( '{0}{1} {2} = "{3}"\r\n'.format( "\t" * level, var_type_str, var_name_str, string ) ) i.v += 3 elif var_type_str == "vector": if (members[i + 1].meta_flag & 0x4000) != 0: align = True append = False sb.append("{0}{1} {2}\r\n".format("\t" * level, var_type_str, var_name_str)) sb.append("{0}{1} {2}\r\n".format("\t" * (level + 1), "Array", "Array")) size = self.reader.read_int() sb.append( "{0}{1} {2} = {3}\r\n".format("\t" * (level + 1), "int", "size", size) ) vector = get_members(members, level, i.v)[3:] i.v += len(vector) + 2 for j in range(size): sb.append("{0}[{1}]\r\n".format("\t" * (level + 2), j)) tmp = RefInt(0) self.read_string_value(sb, vector, tmp) elif var_type_str == "map": if (members[i + 1].meta_flag & 0x4000) != 0: align = True append = False sb.append("{0}{1} {2}\r\n".format("\t" * level, var_type_str, var_name_str)) sb.append("{0}{1} {2}\r\n".format("\t" * (level + 1), "Array", "Array")) size = self.reader.read_int() sb.append( "{0}{1} {2} = {3}\r\n".format("\t" * (level + 1), "int", "size", size) ) map_ = get_members(members, level, i.v)[4:] i.v += len(map_) + 3 first = get_members(map_, map_[0].level, 0) second = map_[len(first) :] for j in range(size): sb.append("{0}[{1}]\r\n".format("\t" * (level + 2), j)) sb.append("{0}{1} {2}\r\n".format("\t" * (level + 2), "pair", "data")) tmp1 = RefInt(0) tmp2 = RefInt(0) self.read_string_value(sb, first, tmp1) self.read_string_value(sb, second, tmp2) elif var_type_str == "TypelessData": append = False size = self.reader.read_int() value = self.reader.read_bytes(size) i.v += 2 sb.append("{0}{1} {2}\r\n".format("\t" * level, var_type_str, var_name_str)) sb.append("{0}{1} {2} = {3}\r\n".format("\t" * level, "int", "size", size)) else: if i != len(members) and members[i + 1].type == "Array": if (members[i + 1].meta_flag & 0x4000) != 0: align = True append = False sb.append( "{0}{1} {2}\r\n".format("\t" * level, var_type_str, var_name_str) ) sb.append("{0}{1} {2}\r\n".format("\t" * (level + 1), "Array", "Array")) size = self.reader.read_int() sb.append( "{0}{1} {2} = {3}\r\n".format( "\t" * (level + 1), "int", "size", size ) ) vector = get_members(members, level, i.v) i.v += len(vector) - 1 vector = vector[3:] # vector.RemoveRange(0, 3) for j in range(size): sb.append("{0}[{1}]\r\n".format("\t" * (level + 2), j)) tmp = RefInt(0) self.read_string_value(sb, vector, tmp) else: append = False sb.append( "{0}{1} {2}\r\n".format("\t" * level, var_type_str, var_name_str) ) eclass = get_members(members, level, i.v) eclass.pop(0) # .RemoveAt(0) i.v += len(eclass) j = RefInt(0) while j < len(eclass): self.read_string_value(sb, eclass, j) j.v += 1 if append: sb.append( "{0}{1} {2} = {3}\r\n".format( "\t" * level, var_type_str, var_name_str, value ) ) if align: self.reader.align_stream() return sb """ def write_u_type(self, obj: dict, members: list) -> bytes: stream = io.BytesIO() write = EndianBinaryReader(stream) for i, member in enumerate(members): var_name_str = member.name write_value(obj[var_name_str], members, write, RefInt(i)) pos = stream.tell() stream.seek(0) ret = stream.read() stream.seek(pos) return ret def write_value(value: dict, members: list, write: EndianBinaryReader, i): member = members[i.v] level = member.level var_type_str = member.type align = (member.meta_flag & 0x4000) != 0 if var_type_str == "SInt8": write.write_s_byte(value) elif var_type_str == "UInt8": write.write_byte(value) elif var_type_str in ["short", "SInt16"]: write.write_short(value) elif var_type_str in ["UInt16", "unsigned short"]: write.write_u_short(value) elif var_type_str in ["int", "SInt32"]: write.write_int(value) elif var_type_str in ["UInt32", "unsigned int", "Type*"]: write.write_u_int(value) elif var_type_str in ["long long", "SInt64"]: write.write_long(value) elif var_type_str in ["UInt64", "unsigned long long"]: write.write_u_long(value) elif var_type_str == "float": write.write_float(value) elif var_type_str == "double": write.write_double(value) elif var_type_str == "bool": write.write_bool(value) elif var_type_str == "string": write.write_aligned_string(value) i.v += 3 elif var_type_str == "map": if (members[i + 1].meta_flag & 0x4000) != 0: align = True dic = list(value.items()) size = len(dic) write.Write(size) map_ = get_members(members, level, i) i.v += len(map_) - 1 map_ = map_[4:] # map.RemoveRange(0, 4) first = get_members(map_, map_[0].level, 0) map_ = map_[len(first):] # .RemoveRange(0, len(first)) second = map_ for j in range(size): tmp1 = RefInt(0) tmp2 = RefInt(0) write_value(dic[j][0], first, write, tmp1) # key write_value(dic[j][1], second, write, tmp2) # value elif var_type_str == "TypelessData": byts = bytes(value) size = len(byts) write.Write(size) write.Write(bytes) i.v += 2 else: if i != len(members) and members[i + 1].type == "Array": # Array if (members[i.v + 1].meta_flag & 0x4000) != 0: align = True list_ = value size = len(list_) write.Write(size) vector = get_members(members, level, i) i.v += len(vector) - 1 vector = vector[3:] # vector.RemoveRange(0, 3) for j in range(size): tmp = RefInt(0) write_value(list_[j], vector, write, tmp) else: # Class eclass = get_members(members, level, i) eclass.pop(0) # .RemoveAt(0) i.v += len(eclass) obj = value j = RefInt(0) while j < len(eclass): classmember = eclass[j.v] name = classmember.name write_value(obj[name], eclass, write, j) if align: write.align_stream(4) """