73 lines
2.1 KiB
Python
73 lines
2.1 KiB
Python
import argparse, os, struct, csv, sys
|
|
|
|
|
|
def align16(x):
|
|
return (x + 15) & ~15
|
|
|
|
|
|
def collect(args):
|
|
items = []
|
|
if args.csv and os.path.exists(args.csv):
|
|
with open(args.csv, newline="", encoding="utf-8") as f:
|
|
for row in csv.DictReader(f):
|
|
items.append((row["name"], row["file"]))
|
|
else:
|
|
for root, dirs, files in os.walk(args.dir):
|
|
for fn in files:
|
|
full = os.path.join(root, fn)
|
|
rel = os.path.relpath(full, args.dir)
|
|
name = rel.replace("/", "\\")
|
|
items.append((name, rel))
|
|
return items
|
|
|
|
|
|
def main():
|
|
ap = argparse.ArgumentParser(description="Rebuild a Dragon .res archive from a directory (16-byte aligned blobs).")
|
|
ap.add_argument("dir")
|
|
ap.add_argument("out")
|
|
ap.add_argument("--csv", default=None)
|
|
args = ap.parse_args()
|
|
|
|
items = collect(args)
|
|
blobs = []
|
|
for name, rel in items:
|
|
full = os.path.join(args.dir, rel)
|
|
if not os.path.isfile(full):
|
|
print("missing: %s" % full, file=sys.stderr)
|
|
sys.exit(2)
|
|
blobs.append((name, open(full, "rb").read()))
|
|
|
|
hdr = 4
|
|
for name, _ in blobs:
|
|
hdr += 4 + len(name) + 8
|
|
data_start = align16(hdr)
|
|
|
|
out = bytearray()
|
|
out += struct.pack("<I", len(blobs))
|
|
index = bytearray()
|
|
offset = data_start
|
|
payload = bytearray()
|
|
for i, (name, blob) in enumerate(blobs):
|
|
nb = name.encode("latin1")
|
|
index += struct.pack("<I", len(nb)) + nb + struct.pack("<II", offset, len(blob))
|
|
payload += blob
|
|
if i != len(blobs) - 1:
|
|
pad = align16(len(blob)) - len(blob)
|
|
payload += b"\x00" * pad
|
|
offset += len(blob) + pad
|
|
else:
|
|
offset += len(blob)
|
|
assert len(index) + 4 == hdr, (len(index) + 4, hdr)
|
|
out += index
|
|
out += b"\x00" * (data_start - len(out))
|
|
out += payload
|
|
|
|
with open(args.out, "wb") as f:
|
|
f.write(out)
|
|
print("repacked %d files -> %s (%d bytes)" % (len(blobs), args.out, len(out)))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|
|
|