import struct from typing import List def u16(b: bytes, o: int) -> int: return b[o] | b[o + 1] << 8 def u32(b: bytes, o: int) -> int: return b[o] | b[o + 1] << 8 | b[o + 2] << 16 | b[o + 3] << 24 def parse_narc(blob: bytes) -> List[bytes]: if blob[:4] != b'NARC': raise ValueError('Not a NARC file') off = 16 if blob[off:off + 4] != b'BTAF': raise ValueError('NARC missing BTAF') btaf_size = u32(blob, off + 4) count = u32(blob, off + 8) entries_off = off + 12 entries = [] for i in range(count): s = u32(blob, entries_off + i * 8) e = u32(blob, entries_off + i * 8 + 4) entries.append((s, e)) fntb_off = off + btaf_size if blob[fntb_off:fntb_off + 4] != b'BTNF': raise ValueError('NARC missing BTNF') fntb_size = u32(blob, fntb_off + 4) fimg_off = fntb_off + fntb_size if blob[fimg_off:fimg_off + 4] != b'GMIF': raise ValueError('NARC missing GMIF') base = fimg_off + 8 files = [] for s, e in entries: files.append(blob[base + s:base + e]) return files def build_narc(files: List[bytes]) -> bytes: def align4(n: int) -> int: return n + 3 & ~3 def pad4(data: bytes) -> bytes: padding = -len(data) & 3 return data + b'\x00' * padding gmif_data = bytearray() file_offsets = [] for file_data in files: file_offsets.append(len(gmif_data)) gmif_data.extend(file_data) padding = -len(gmif_data) & 3 if padding: gmif_data.extend(b'\x00' * padding) file_offsets.append(len(gmif_data)) gmif_size = 8 + len(gmif_data) gmif_section = b'GMIF' + struct.pack('