"""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)