69 lines
2.1 KiB
Python
69 lines
2.1 KiB
Python
import argparse, os, struct, csv, hashlib, sys
|
|
|
|
|
|
def read_index(path):
|
|
data = open(path, "rb").read()
|
|
count = struct.unpack_from("<I", data, 0)[0]
|
|
p = 4
|
|
entries = []
|
|
for i in range(count):
|
|
ln = struct.unpack_from("<I", data, p)[0]
|
|
p += 4
|
|
name = data[p:p + ln].decode("latin1")
|
|
p += ln
|
|
off, size = struct.unpack_from("<II", data, p)
|
|
p += 8
|
|
entries.append((name, off, size))
|
|
return data, entries, p
|
|
|
|
|
|
def safe_rel(name):
|
|
rel = name.replace("\\", os.sep).replace("/", os.sep)
|
|
parts = [x for x in rel.split(os.sep) if x not in ("", ".", "..")]
|
|
return os.path.join(*parts) if parts else "_unnamed"
|
|
|
|
|
|
def main():
|
|
ap = argparse.ArgumentParser(description="Extract the Dragon .res archive (index + raw blobs).")
|
|
ap.add_argument("res")
|
|
ap.add_argument("out")
|
|
ap.add_argument("--csv", default=None)
|
|
args = ap.parse_args()
|
|
|
|
data, entries, header_end = read_index(args.res)
|
|
os.makedirs(args.out, exist_ok=True)
|
|
rows = []
|
|
used = set()
|
|
for name, off, size in entries:
|
|
rel = safe_rel(name)
|
|
dst = os.path.join(args.out, rel)
|
|
base, ext = os.path.splitext(dst)
|
|
n = 1
|
|
while dst.lower() in used:
|
|
dst = "%s__%d%s" % (base, n, ext)
|
|
n += 1
|
|
used.add(dst.lower())
|
|
os.makedirs(os.path.dirname(dst), exist_ok=True)
|
|
blob = data[off:off + size]
|
|
with open(dst, "wb") as f:
|
|
f.write(blob)
|
|
rows.append({
|
|
"name": name,
|
|
"offset": off,
|
|
"size": size,
|
|
"file": os.path.relpath(dst, args.out),
|
|
"sha1": hashlib.sha1(blob).hexdigest(),
|
|
})
|
|
print("[%4d/%d] %s (%d bytes)" % (len(rows), len(entries), name, size))
|
|
|
|
if args.csv:
|
|
with open(args.csv, "w", newline="", encoding="utf-8") as f:
|
|
w = csv.DictWriter(f, fieldnames=["name", "offset", "size", "file", "sha1"])
|
|
w.writeheader()
|
|
w.writerows(rows)
|
|
print("done: %d files -> %s" % (len(rows), args.out))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|