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>
76 lines
2.5 KiB
Python
76 lines
2.5 KiB
Python
"""Decompressore Unix compress (.Z, LZW) minimale, come ncompress."""
|
|
import sys, os
|
|
|
|
|
|
def unz(data):
|
|
assert data[0] == 0x1f and data[1] == 0x9d, "non e' un flusso .Z"
|
|
flags = data[2]
|
|
maxbits = flags & 0x1f
|
|
block = bool(flags & 0x80)
|
|
out = bytearray()
|
|
n_bits = 9
|
|
maxcode = (1 << n_bits) - 1
|
|
table = {i: bytes([i]) for i in range(256)}
|
|
free = 257 if block else 256
|
|
pos = 3 * 8 # posizione in bit
|
|
total = len(data) * 8
|
|
start = pos # inizio del gruppo corrente di codici (per il riallineamento)
|
|
old = None
|
|
while pos + n_bits <= total:
|
|
byte = pos >> 3
|
|
chunk = int.from_bytes(data[byte:byte + 4], 'little')
|
|
code = (chunk >> (pos & 7)) & ((1 << n_bits) - 1)
|
|
pos += n_bits
|
|
if old is None:
|
|
old = table[code]
|
|
out += old
|
|
continue
|
|
if code == 256 and block:
|
|
table = {i: bytes([i]) for i in range(256)}
|
|
free = 256
|
|
# riallinea a multipli di 8 codici
|
|
grp = n_bits * 8
|
|
pos = start + ((pos - start + grp - 1) // grp) * grp
|
|
n_bits = 9
|
|
maxcode = (1 << n_bits) - 1
|
|
start = pos
|
|
old = None
|
|
free = 257
|
|
continue
|
|
if code in table:
|
|
entry = table[code]
|
|
elif code == free:
|
|
entry = old + old[:1]
|
|
else:
|
|
raise ValueError(f"codice LZW non valido {code} (free={free}) a bit {pos}")
|
|
out += entry
|
|
if free <= (1 << maxbits) - 1:
|
|
table[free] = old + entry[:1]
|
|
free += 1
|
|
old = entry
|
|
if free > maxcode and n_bits < maxbits:
|
|
grp = n_bits * 8
|
|
pos = start + ((pos - start + grp - 1) // grp) * grp
|
|
n_bits += 1
|
|
maxcode = (1 << n_bits) - 1
|
|
start = pos
|
|
return bytes(out)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
import prt
|
|
d, secs, order = prt.load(sys.argv[1])
|
|
outdir = sys.argv[2]
|
|
for n in order:
|
|
o, l, f = secs[n]
|
|
b = d[o:o + l]
|
|
if b[:2] == b'\x1f\x9d':
|
|
try:
|
|
u = unz(b)
|
|
except Exception as e:
|
|
print(n, 'ERR', e)
|
|
continue
|
|
print(n, 'compressa', l, '->', len(u), 'dichiarata', int(f[0], 16), u[:60])
|
|
open(os.path.join(outdir, n.replace(':', '_') + '.bin'), 'wb').write(u)
|