forked from real-pmein1/stmsrvemu
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgcf_to_storage.py
193 lines (151 loc) · 6.71 KB
/
gcf_to_storage.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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
import logging
import os
import sys
import time
import zlib
import config
import globalvars
from utilities import storages
from utilities.checksums import Checksums
from utilities.gcf import GCF
config = config.read_config()
def create_progress_bar(total, filename):
if config["show_convert_bar"].lower() == "true":
try:
from tqdm import tqdm
print("Converting File: " + filename)
return tqdm(total = total, unit = "file", dynamic_ncols = False)
except ImportError:
pass
# Return None when show_convert_bar is false
return None
def compare_checksums(less, more):
for fileid in range(less.numfiles):
if less.checksums_raw[fileid] != more.checksums_raw[fileid]:
print(f"Checksums doesn't match for file {fileid} {len(less.checksums_raw[fileid])} {len(more.checksums_raw[fileid])}")
sys.exit()
def gcf2storage(filename):
log = logging.getLogger("converter")
is_wan_file = filename.endswith("_wan.neutered.gcf")
is_lan_file = filename.endswith("_lan.neutered.gcf")
file_suffix = "_wan" if is_wan_file else "_lan" if is_lan_file else ""
do_updates = True
gcf = GCF(filename)
progress_bar = create_progress_bar(len(gcf.manifest.dir_entries), filename)
manifestdir = "files/cache/" + str(gcf.appid) + "_" + str(gcf.appversion) + "/"
storagedir = "files/cache/" + str(gcf.appid) + "_" + str(gcf.appversion) + "/"
if not os.path.isdir(manifestdir):
os.makedirs(manifestdir, exist_ok = True)
storage = storages.Old_Storage(gcf.appid, storagedir, file_suffix)
manifest_filename = os.path.join(manifestdir, f"{gcf.appid}_{gcf.appversion}.manifest")
if os.path.isfile(manifest_filename):
f = open(manifest_filename, "rb")
stored_manifest_data = f.read()
f.close()
if stored_manifest_data != gcf.manifest_data:
print("Manifests differ!!")
sys.exit() # else: # print("Manifests match, continuing..")
else:
# print "New manifest"
# we write a new manifest anyway
f = open(manifest_filename, "wb")
f.write(gcf.manifest_data)
f.close()
gcf_checksums = Checksums(gcf.checksum_data)
checksum_filename = os.path.join(storagedir, f"{gcf.appid}{file_suffix}.checksums")
if os.path.isfile(checksum_filename):
stored_checksums = Checksums()
stored_checksums.load_from_file(checksum_filename)
if gcf_checksums.numfiles > stored_checksums.numfiles:
print("Checksums in GCF have more files than checksums in storage")
compare_checksums(stored_checksums, gcf_checksums)
if do_updates:
timex = str(int(time.time()))
os.rename(checksum_filename, checksum_filename + "." + timex + ".bak")
f = open(checksum_filename, "wb")
f.write(gcf.checksum_data)
f.close()
else:
print("Checksums in storage have equal or more files than checksums in GCF")
compare_checksums(gcf_checksums, stored_checksums)
else:
if do_updates:
f = open(checksum_filename, "wb")
f.write(gcf.checksum_data)
f.close()
# print "Checking files "
for (dirid, d) in gcf.manifest.dir_entries.items():
if progress_bar:
progress_bar.update(1) # Increment the progress bar
if d.fileid == 0xffffffff:
continue
if gcf_checksums.numchecksums[d.fileid] == 0:
continue
if d.dirtype & 0x100:
print(f"File encrypted {d.fileid}")
continue
if d.fileid not in storage.indexes:
# print "File not in storage", d.fileid, d.fullfilename
if d.dirtype & 0x100:
file = []
for gcf_block in gcf.get_file(dirid):
file.append(gcf_block)
file = b"".join(file) # print binascii.b2a_hex(file[:64])
else:
if do_updates:
file = []
for gcf_block in gcf.get_file(dirid):
file.append(gcf_block)
file = b"".join(file)
if len(file) != d.itemsize:
print(f"Length of extracted file and file size doesn't match! {len(file)} {d.itemsize}")
sys.exit()
chunks = []
chunkid = 0
for start in range(0, len(file), 32768):
chunk = file[start:start + 32768]
if not gcf_checksums.validate_chunk(d.fileid, chunkid, chunk, checksum_filename):
# print "Checksum failed!"
# failed = "1"
log.debug("Checksum fixed!") # sys.exit()
chunks.append(zlib.compress(chunk, 9))
chunkid += 1
# print "Writing file to storage", d.fullfilename, len(file)
storage.writefile(d.fileid, chunks, 1)
continue
else:
if storage.filemodes[d.fileid] == 2 or storage.filemodes[d.fileid] == 3:
print(f"File is encrypted in storage but not in GCF {d.fileid}")
sys.exit()
storage_chunk = b""
storage_chunkid = 0
gcf_chunk = b""
totalsize = 0
for gcf_block in gcf.get_file(dirid):
if not storage_chunk:
(storage_chunk, filemode) = storage.readchunk(d.fileid, storage_chunkid)
if len(storage_chunk):
storage_chunk = zlib.decompress(storage_chunk)
gcf_chunk += gcf_block
totalsize += len(gcf_block)
if len(gcf_chunk) >= len(storage_chunk):
if gcf_chunk != storage_chunk:
print(f"Difference between chunks!!! {len(gcf_chunk)} {len(storage_chunk)}")
sys.exit()
else:
# print "\b.",
pass
storage_chunk = b""
storage_chunkid += 1
gcf_chunk = b""
# print storage_chunkid, gcf_checksums.numchecksums[d.fileid]
if totalsize != d.itemsize:
print("")
print(f"Different sizes, file incomplete? {d.fileid} {totalsize} {d.itemsize}") # sys.exit()
else:
print("\b.", end = ' ')
if progress_bar:
progress_bar.close() # Close the progress bar when don
globalvars.hide_convert_prints = False
if __name__ == "__main__":
gcf2storage(sys.argv[1])