Files
prep-step/scripts/psb/unz.py
T
davideandClaude 2d7ace07e2 Documenta il formato PSB dei file Creo e aggiungi il parser di riferimento
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>
2026-11-10 14:34:29 +01:00

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)