-
Notifications
You must be signed in to change notification settings - Fork 7
/
fix_cob_after_spring_4785bdcc.py
79 lines (64 loc) · 2.42 KB
/
fix_cob_after_spring_4785bdcc.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
#!/usr/bin/env python2
# This file is part of the Spring engine (GPL v2 or later), see LICENSE.html
# written by ashdnazg to help convert unit scripts after 4785bdcc
import sys
import struct
import glob
import os.path
COB_HEADER_FORMAT = "<13L"
COB_HEADER_FIELDS = (
"VersionSignature",
"NumberOfScripts",
"NumberOfPieces",
"TotalScriptLen",
"NumberOfStaticVars",
"Unknown_2",
"OffsetToScriptCodeIndexArray",
"OffsetToScriptNameOffsetArray",
"OffsetToPieceNameOffsetArray",
"OffsetToScriptCode",
"Unknown_3",
"OffsetToSoundNameArray",
"NumberOfSounds"
)
OLD_RETURN = struct.pack("<3L", 0x10021001, 0, 0x10065000)
NEW_RETURN = struct.pack("<3L", 0x10021002, 1, 0x10065000)
def unpack(bytes, offset, format):
return struct.unpack(format, bytes[offset:offset+struct.calcsize(format)])
def unpack_string(bytes, offset):
b = bytes[offset:]
return b[:b.index('\0')]
def process_cob(path):
print("processing %s" % (path,))
content = open(path, "rb").read()
header_values = unpack(content, 0, COB_HEADER_FORMAT)
header = dict(zip(COB_HEADER_FIELDS, header_values))
name_offset_array = header["OffsetToScriptNameOffsetArray"]
code_offset_array = header["OffsetToScriptCodeIndexArray"]
script_names = []
script_code_offsets = []
for i in range(header["NumberOfScripts"]):
(script_name_offset,) = unpack(content, name_offset_array + i * 4, "<L")
(script_code_offset,) = unpack(content, code_offset_array + i * 4, "<L")
script_names.append(unpack_string(content, script_name_offset))
script_code_offsets.append(script_code_offset)
script_code_offsets.append(header["TotalScriptLen"])
if "Killed" not in script_names:
return
killed_index = script_names.index("Killed")
killed_offset = script_code_offsets[killed_index] * 4
killed_len = script_code_offsets[killed_index + 1] * 4 - killed_offset
base_offset = header["OffsetToScriptCode"]
killed_content = content[base_offset + killed_offset:base_offset + killed_offset + killed_len]
killed_content = killed_content.replace(OLD_RETURN, NEW_RETURN)
new_content = content[:base_offset + killed_offset] + killed_content + content[base_offset + killed_offset + killed_len:]
open(path, "wb").write(new_content)
def main(root_folder):
cob_paths = glob.glob(os.path.join(root_folder, "*.[Cc][Oo][Bb]"))
for cob_path in cob_paths:
process_cob(cob_path)
if __name__ == '__main__':
if len(sys.argv) < 2:
print("Usage: %s <cob root folder>" % (sys.argv[0],))
exit(1)
main(sys.argv[1])