#!/usr/bin/env python3 import struct, zlib, re, os MOD=0x00FFF9D7; RECIP=0x80031493 def rol(v,n,b=32): v&=(1<>(b-n)))&((1<>32)&0xFFFFFFFF; q=rol(hi,9)&0x1FF a=(a-(q*MOD))&0xFFFFFFFF return (((bb<<24)&0xFF000000)|(a&0xFFFFFF))&0xFFFFFFFF EX="/home/fabi/RE Project Sylpheed/sylph_extract" def load_pak(base): """base like dat/movie/eng ; returns list of (hash,off,size), data bytes""" pak=open(f"{EX}/{base}.pak","rb").read() n=struct.unpack(">I",pak[4:8])[0] es=[struct.unpack(">III",pak[16+12*i:28+12*i]) for i in range(n)] p00=f"{EX}/{base}.p00" data=open(p00,"rb").read() if os.path.exists(p00) else pak return es, data def unz(blob): if blob[:2]==b'Z1': zi=blob.find(b'\x78\xda'); if zi<0: zi=blob.find(b'\x78\x9c') return zlib.decompress(blob[zi:]) return blob # --- verify the track key scheme --- es,data=load_pak("dat/movie/eng") keys={h for h,_,_ in es} for mv,exp in [("S00A",0x6F2D9663),("hokyu_DS_s02A",0x3662B1F8),("RT01C_1",0x756F69FB),("S16A",0xEEB85377)]: k=nh(f"subtitle_{mv}.tbl") print(f"subtitle_{mv}.tbl -> {k:08X} expect {exp:08X} inpak={k in keys} {'OK' if k==exp else 'MISMATCH'}") # --- build MSG_DEMO text table from GP_MAIN_GAME_E --- es2,data2=load_pak("dat/GP_MAIN_GAME_E") text={} # 'MSG_DEMO_ddd_ppp_ll' -> string keyrx=re.compile(r'^MSG_DEMO_\d+(_\d+)*$') for h,o,s in es2: dec=unz(data2[o:o+s]) if dec[:4]!=b'IXUD': continue # walk null-terminated utf-16le strings in the whole block toks=re.findall(rb'(?:[\x20-\x7e]\x00){2,}', dec) toks=[t.decode('utf-16-le') for t in toks] # pair: text followed by its key for i in range(len(toks)-1): if keyrx.match(toks[i+1]) and not keyrx.match(toks[i]): text[toks[i+1]]=toks[i] print(f"\nMSG_DEMO text lines loaded: {len(text)}") # --- render a movie's subtitle transcript --- def track_for(mv): k=nh(f"subtitle_{mv}.tbl") for h,o,s in es: if h==k: return unz(data[o:o+s]) return None # index text by integer demo id -> ordered list of lines bydemo={} for k,v in text.items(): m=re.match(r'MSG_DEMO_(\d+)_',k) if m: bydemo.setdefault(int(m.group(1)),[]).append((k,v)) for d in bydemo: bydemo[d].sort() def transcript(mv): dec=track_for(mv) if not dec: return f"[no track for {mv}]" toks=re.findall(rb'(?:[\x20-\x7e]\x00){2,}', dec) toks=[t.decode('utf-16-le') for t in toks] out=[f"=== {mv}.wmv ==="] # collect all MSG_DEMO ids and timecodes in order; pair positionally seq=[('id',int(re.match(r'MSG_DEMO_(\d+)$',t).group(1))) if re.match(r'MSG_DEMO_(\d+)$',t) else ('tc',t) if re.match(r'\d\d:\d\d\.\d\d$',t) else ('x',t) for t in toks] ids=[v for k,v in seq if k=='id']; tcs=[v for k,v in seq if k=='tc'] for j,demo in enumerate(ids): tc=tcs[j] if j