forked from LagoLunatic/wwrando
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfs_helpers.py
153 lines (117 loc) · 3.88 KB
/
fs_helpers.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
import struct
class InvalidOffsetError(Exception):
pass
def data_len(data):
data_length = data.seek(0, 2)
return data_length
def read_bytes(data, offset, length):
data.seek(offset)
return data.read(length)
def write_bytes(data, offset, raw_bytes):
data.seek(offset)
data.write(raw_bytes)
def read_and_unpack_bytes(data, offset, length, format_string):
data.seek(offset)
requested_data = data.read(length)
unpacked_data = struct.unpack(format_string, requested_data)
return unpacked_data
def write_and_pack_bytes(data, offset, new_values, format_string):
packed_data = struct.pack(format_string, *new_values)
data.seek(offset)
data.write(packed_data)
def read_str(data, offset, length):
data_length = data.seek(0, 2)
if offset+length > data_length:
raise InvalidOffsetError("Offset %X, length %X is past the end of the data (length %X)." % (offset, length, data_length))
data.seek(offset)
string = data.read(length).decode("ascii")
string = string.rstrip("\0") # Remove trailing null bytes
return string
def try_read_str(data, offset, length):
try:
return read_str(data, offset, length)
except UnicodeDecodeError:
return None
except InvalidOffsetError:
return None
def read_str_until_null_character(data, offset):
data_length = data.seek(0, 2)
if offset > data_length:
raise InvalidOffsetError("Offset %X is past the end of the data (length %X)." % (offset, data_length))
str = ""
while offset < data_length:
data.seek(offset)
char = data.read(1)
if char == b"\0":
break
else:
str += char.decode("ascii")
offset += 1
return str
def write_str(data, offset, new_string, max_length):
str_len = len(new_string)
if str_len > max_length:
raise Exception("String %s is too long (max length %X)" % (new_string, max_length))
padding_length = max_length - str_len
null_padding = b"\x00"*padding_length
new_value = new_string.encode("ascii") + null_padding
data.seek(offset)
data.write(new_value)
def write_str_with_null_byte(data, offset, new_string):
str_len = len(new_string)
write_str(data, offset, new_string, str_len+1)
def read_u8(data, offset):
data.seek(offset)
return struct.unpack(">B", data.read(1))[0]
def read_u16(data, offset):
data.seek(offset)
return struct.unpack(">H", data.read(2))[0]
def read_u32(data, offset):
data.seek(offset)
return struct.unpack(">I", data.read(4))[0]
def read_float(data, offset):
data.seek(offset)
return struct.unpack(">f", data.read(4))[0]
def read_s8(data, offset):
data.seek(offset)
return struct.unpack(">b", data.read(1))[0]
def read_s16(data, offset):
data.seek(offset)
return struct.unpack(">h", data.read(2))[0]
def read_s32(data, offset):
data.seek(offset)
return struct.unpack(">i", data.read(4))[0]
def write_u8(data, offset, new_value):
new_value = struct.pack(">B", new_value)
data.seek(offset)
data.write(new_value)
def write_u16(data, offset, new_value):
new_value = struct.pack(">H", new_value)
data.seek(offset)
data.write(new_value)
def write_u32(data, offset, new_value):
new_value = struct.pack(">I", new_value)
data.seek(offset)
data.write(new_value)
def write_float(data, offset, new_value):
new_value = struct.pack(">f", new_value)
data.seek(offset)
data.write(new_value)
def write_s8(data, offset, new_value):
new_value = struct.pack(">b", new_value)
data.seek(offset)
data.write(new_value)
def write_s16(data, offset, new_value):
new_value = struct.pack(">h", new_value)
data.seek(offset)
data.write(new_value)
def write_s32(data, offset, new_value):
new_value = struct.pack(">i", new_value)
data.seek(offset)
data.write(new_value)
def align_data_to_nearest(data, size):
current_end = data_len(data)
next_offset = current_end + (size - current_end % size) % size
padding_needed = next_offset - current_end
data.seek(current_end)
data.write(b"\0"*padding_needed)