Reverse engineering di 9253000117a.prt.35: contenitore (offset dall'ultimo campo dell'intestazione, indice a catena), grammatica completa delle sezioni (id progressivi dei campi, tabella "dopo X viene Y", marcatori di chiusura), tabella dei double verificata sulla norma delle matrici, sezioni compresse e catalogo del contenuto. Parser Python in scripts/psb/. docs/history.md raccoglie stato, metodo e punti aperti per riprendere il lavoro. Co-Authored-By: Claude <noreply@anthropic.com>
41 lines
1.5 KiB
Python
41 lines
1.5 KiB
Python
import sys,re
|
|
sys.stdout.reconfigure(encoding='utf-8',errors='replace')
|
|
def load(p):
|
|
d=open(p,'rb').read()
|
|
base=int(d[:d.find(b'\n')].split()[-2],16)
|
|
secs={}
|
|
order=[]
|
|
i=d.find(b'#UGC_TOC')
|
|
while True:
|
|
e=d.find(b'\n',i); pos=e+1; nxt=None
|
|
while True:
|
|
e2=d.find(b'\n',pos); line=d[pos:e2]
|
|
if line.startswith(b'#'): break
|
|
f=line.rstrip(b'#').split()
|
|
name=f[0].decode('latin1'); off=int(f[1],16); ln=int(f[2],16)
|
|
if name=='NEXT_TOC_ENTRY': nxt=base+off
|
|
else:
|
|
mk=len(name)+2
|
|
secs[name]=(base+off+mk,ln-mk,[x.decode() for x in f[3:]]); order.append(name)
|
|
pos=e2+1
|
|
if nxt is None: break
|
|
i=nxt
|
|
return d,secs,order
|
|
def sec(p,name):
|
|
d,secs,_=load(p); o,l,_=secs[name]; return d[o:o+l]
|
|
def hexdump(b,start=0,n=None,w=32):
|
|
b=b[start:start+n] if n else b[start:]
|
|
for i in range(0,len(b),w):
|
|
c=b[i:i+w]
|
|
print(f"{start+i:6x} "+' '.join(f"{x:02x}" for x in c).ljust(w*3)+' '+''.join(chr(x) if 32<=x<127 else '.' for x in c))
|
|
if __name__=='__main__':
|
|
d,secs,order=load(sys.argv[1])
|
|
if len(sys.argv)>2:
|
|
o,l,_=secs[sys.argv[2]]; b=d[o:o+l]
|
|
st=int(sys.argv[3],0) if len(sys.argv)>3 else 0
|
|
n=int(sys.argv[4],0) if len(sys.argv)>4 else None
|
|
hexdump(b,st,n)
|
|
else:
|
|
for nme in order:
|
|
o,l,f=secs[nme]; print(f"{nme:26} {o:8} {l:8} {' '.join(f):34} {d[o:o+20]!r}")
|