-
Notifications
You must be signed in to change notification settings - Fork 5
/
chksum.py
executable file
·87 lines (71 loc) · 2.2 KB
/
chksum.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
#!/usr/bin/env python3
# fixes the checksums in a Majora's Mask savefile for Bizhawk
# note: copies are ignored and overwritten, so don't bother editing them.
import sys
from util import R2, W2, swap_order
lament = lambda *args, **kwargs: print(*args, file=sys.stderr, **kwargs)
MAX16 = 0xFFFF
chksum_offset = 0x100A
save_size = 0x2000
owl_size = 0x4000
save_1 = (0x20800, save_size)
save_2 = (0x24800, save_size)
owl_1 = (0x28800, owl_size)
owl_2 = (0x30800, owl_size)
save_1_copy = (0x22800, save_size)
save_2_copy = (0x26800, save_size)
owl_1_copy = (0x2C800, owl_size)
owl_2_copy = (0x34800, owl_size)
def calc_sum(data):
chksum = 0
for b in data:
chksum += b
chksum &= MAX16
return chksum
def fix_sum(f, save, owl=False):
f.seek(save[0])
data = f.read(save[1])
chksum = calc_sum(data[:chksum_offset])
if owl and data != b'\x00'*len(data):
chksum += 0x24 # don't know why
chksum &= MAX16
f.seek(save[0] + chksum_offset)
old_chksum = R2(f.read(2))
f.seek(save[0] + chksum_offset)
f.write(W2(chksum))
lament('{:04X} -> {:04X}'.format(old_chksum, chksum))
def copy_save(f, save_from, save_to):
f.seek(save_from[0])
data = f.read(save_from[1])
f.seek(save_to[0])
f.write(data[:save_to[1]])
def delete_save(f, save):
f.seek(save[0])
f.write(b'\x00'*save[1])
def run(args):
for fn in args:
with open(fn, 'r+b') as f:
# dumb way to determine byte order
endian = 'big'
f.seek(0x10000)
if f.read(4) != b'\x03\x00\x03\x00':
endian = 'little'
if endian == 'little':
swap_order(f, 'L')
fix_sum(f, save_1)
fix_sum(f, save_2)
fix_sum(f, owl_1, owl=True)
fix_sum(f, owl_2, owl=True)
copy_save(f, save_1, save_1_copy)
copy_save(f, save_2, save_2_copy)
copy_save(f, owl_1, owl_1_copy)
copy_save(f, owl_2, owl_2_copy)
if endian == 'little':
swap_order(f, 'L')
return 0
if __name__ == '__main__':
try:
ret = run(sys.argv[1:])
sys.exit(ret)
except KeyboardInterrupt:
sys.exit(1)