Initial commit: RE tooling and docs for The I of the Dragon localization/HD

This commit is contained in:
DragonHD
2026-09-20 09:57:07 +08:00
commit caf7376019
26 changed files with 1624 additions and 0 deletions
+68
View File
@@ -0,0 +1,68 @@
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()