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>
This commit is contained in:
1 parent
1eac3ccaa7
commit
2d7ace07e2
15 files changed
+1309
No files matched your search
@@ -0,0 +1,75 @@
|
||||
"""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)
|
||||
Reference in new issue
Block a user