Created
January 5, 2023 15:11
-
-
Save Wh1terat/72af90a73e2eb7a9e0522c3992859067 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import argparse | |
from pathlib import Path | |
from struct import pack, unpack, iter_unpack | |
__title__ = "Xanavi RCL (Un)packer" | |
__version__ = "0.1" | |
__author__ = "Gareth Bryan" | |
__license__ = "MIT" | |
def main(args): | |
if args.action == 'p': | |
rcl_pack(args.indir, args.outfile) | |
elif args.action == 'u': | |
rcl_unpack(args.infile, args.outdir) | |
def rcl_pack(indir, outfile): | |
table_len = sum(16 for _ in indir.glob('*.png')) | |
header = bytearray(0x118) | |
table = bytearray() | |
data = bytearray() | |
header[0x00:0x20] = b'Xanavi Informatics Corporation'.ljust(0x20, b'\x00') | |
header[0x20:0x50] = b'20080722-125925 08IT_OPENING_M3H'.ljust(0x30, b'\x00') | |
header[0x50:0x70] = b'M3H'.ljust(0x20, b'\x00') | |
header[0x70:0x74] = b'\xFF\xFF\x00\x01' # Type? | |
header[0x74:0x78] = b'\xFF\xFF\xFF\xFF' | |
header[0x7C:0x80] = b'\xFF\xFF\xFF\xFF' | |
header[0x100:0x104] = pack('>I', 0x108) | |
header[0x104:0x108] = pack('>I', 0x10C) | |
header[0x108:0x10C] = pack('>I', 12) | |
header[0x10C:0x110] = pack('>I', 8) | |
header[0x110:0x114] = pack('>I', 0x114) | |
# Write file data start | |
header[0x114:0x118] = pack('>I', table_len + 4) | |
# Loop through PNGs | |
for p in sorted(indir.glob('*.png')): | |
offset = len(header) + table_len + len(data) | |
# Add file table entry | |
table.extend( | |
pack( | |
">4I", | |
offset, offset, p.stat().st_size, p.stat().st_size | |
) | |
) | |
with p.open('rb') as f: | |
# Add png to data bytearray | |
data.extend(f.read()) | |
# Align file to 4 bytes | |
if len(data) % 4: | |
padding = b'\x00' * (4 - (len(data) % 4)) | |
data.extend(padding) | |
# Set filesize in header | |
header[0x78:0x7C] = pack('>I', len(header)+len(table)+len(data)) | |
# Write output | |
outfile.write(header) | |
outfile.write(table) | |
outfile.write(data) | |
def rcl_unpack(infile, outdir): | |
infile = infile.read() | |
outdir.mkdir() | |
table_start, table_len = unpack('>2I', infile[0x110:0x118]) | |
for i, entry in enumerate(iter_unpack('>I4xI4x', infile[table_start+4:table_start+table_len])): | |
offset, size = entry | |
png = f'{outdir}/{i:03d}.png' | |
#print(png, entry) | |
with open(png, 'wb') as f: | |
f.write(infile[offset:offset+size]) | |
if __name__ == "__main__": | |
parser = argparse.ArgumentParser( | |
description="{} v{}".format(__title__, __version__) | |
) | |
subparsers = parser.add_subparsers(title="Actions", dest="action", required=True) | |
act_pack = subparsers.add_parser("p", help="Pack") | |
act_pack.add_argument( | |
"indir", | |
help="Input dir", | |
type=Path, | |
nargs="?", | |
) | |
act_pack.add_argument( | |
"outfile", | |
help="Output RCL file", | |
type=argparse.FileType("wb"), | |
nargs="?", | |
) | |
act_unpack = subparsers.add_parser("u", help="Unpack") | |
act_unpack.add_argument( | |
"infile", | |
help="Input RCL file", | |
type=argparse.FileType("rb"), | |
nargs="?", | |
) | |
act_unpack.add_argument( | |
"outdir", | |
help="Output dir", | |
type=Path, | |
nargs="?", | |
) | |
args = parser.parse_args() | |
main(args) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment