#!/usr/bin/env python3
"""Extracteur d'archive PyInstaller (CArchive) — sort chaque entrée sur disque."""
import struct, sys, zlib, os

MAGIC = b"MEI\014\013\012\013\016"

def main(path, outdir):
    d = open(path, "rb").read()
    cp = d.rfind(MAGIC)
    if cp < 0:
        print("cookie absent"); return
    # cookie = magic(8) + lengthofPackage(4) + toc(4) + tocLen(4) + pyvers(4) + pylibname(64)
    magic, pkglen, toc, tocLen, pyvers, pylib = struct.unpack("!8sIIII64s", d[cp:cp+88])
    pylib = pylib.rstrip(b"\0").decode("latin1")
    overlay = len(d) - pkglen
    tocpos = overlay + toc
    print(f"  archive     : offset 0x{overlay:x}, {pkglen} o")
    print(f"  TOC         : offset 0x{tocpos:x}, {tocLen} o")
    print(f"  Python      : {pyvers//100}.{pyvers%100}   lib: {pylib}\n")

    os.makedirs(outdir, exist_ok=True)
    p, entries = tocpos, []
    while p < tocpos + tocLen:
        (elen,) = struct.unpack("!I", d[p:p+4])
        if elen <= 0: break
        epos, csize, usize, flag = struct.unpack("!IIIB", d[p+4:p+17])
        etype = d[p+17:p+18].decode("latin1")
        name = d[p+18:p+elen].rstrip(b"\0").decode("latin1", "replace")
        entries.append((name, etype, epos, csize, usize, flag))
        p += elen

    print(f"  {len(entries)} entrées\n")
    interesting = []
    for name, etype, epos, csize, usize, flag in entries:
        raw = d[overlay+epos: overlay+epos+csize]
        if flag:
            try: raw = zlib.decompress(raw)
            except Exception: pass
        # 's'=script  'm'/'M'=module  'z'/'Z'=PYZ  'b'=binaire  'x'=data
        if etype in ("s", "m", "M", "z", "Z"):
            interesting.append((name, etype, len(raw)))
        safe = name.replace("\\", "_").replace("/", "_").replace(":", "_") or "unnamed"
        open(os.path.join(outdir, f"{etype}__{safe}"), "wb").write(raw)

    print("  ── scripts, modules et PYZ (le code du programme) ──")
    for n, t, s in sorted(interesting, key=lambda x: -x[2]):
        print(f"    [{t}] {n:<44} {s:>10} o")

main(sys.argv[1], sys.argv[2])
