"""VERIFY PASS 3.

Attacks:
  D1-10 FutUserCredits(0x180122c50) / FutSBCSubmitChallenge(0x180161b00) key sets
  D1-9  packList parser 0x18017fc20 and its element parser 0x18017f830
  D1-8  tile 0x1c CentralUnclaimedPack in FUN_1800b2680
  D2-2  reveal-screen reader FUN_18009bc40 (does it gate on card+0x10?)
  D2-6  discardValue client fallback inside FUN_18013fe00 (print the guard region)
  D2-7  bounded-negative: who reads FutDiscardCardServerResponse+0x28
  Also: xrefs to the two ByRes deserializers, and whether chemistry(0x81) appears
        in FutMoveCardByRes 0x180128e30 (docs put chemistry on MoveCard).
"""
import traceback

OUT = "/tmp/claude-1000/-home-alex-Documents-OpenFUT/8e521ca1-ca3e-4138-bb96-df1744dd1d30/scratchpad/packres/v3_raw.txt"

try:
    lines = []
    def P(*a):
        s = " ".join(str(x) for x in a)
        print(s)
        lines.append(s)

    for va, tag in [(0x180122c50, "D1-10 FutUserCreditsServerResponse deser"),
                    (0x180161b00, "D1-10 FutSBCSubmitChallengeServerResponse deser"),
                    (0x18017fc20, "D1-9 packList root parser"),
                    (0x18017f830, "D1-9 packList element parser"),
                    (0x18009bc40, "D2-2 pack-reveal controller"),
                    (0x180128e30, "D2-9 FutMoveCardByRes deser (chemistry?)"),
                    (0x1801279c0, "D2-5 FutDiscardCardByRes deser")]:
        f = func(va)
        src = dec(va)
        P("")
        P("=" * 70)
        P("### %s @ %#x fname=%s entry=%s len(src)=%d" %
          (tag, va, fname(va) if f else "?",
           hex(int(f.getEntryPoint().getOffset())) if f else "NONE", len(src)))
        P("=" * 70)
        P(src)

    # discardValue fallback: print the item deser around the fcc_discardcoins site
    P("")
    P("=" * 70)
    src = dec(0x18013fe00)
    P("### D2-6 item element deser 0x18013fe00 len(src)=%d" % len(src))
    P("=" * 70)
    L = src.split("\n")
    idx = [i for i, l in enumerate(L) if "fcc_discardcoins" in l or "discardValue" in l
           or '"price"' in l or '"rare"' in l or '"level"' in l or '"cardtype"' in l]
    P("marker lines: %s" % idx)
    lo = max(0, min(idx) - 45) if idx else 0
    hi = min(len(L), max(idx) + 30) if idx else 0
    for i in range(lo, hi):
        P("%5d %s" % (i, L[i]))
    P("--- all lines mentioning 0xd7 (discardValue atom) ---")
    for i, l in enumerate(L):
        if "0xd7" in l:
            P("%5d %s" % (i, l))

    # D2-7 bounded negative, done a different way: every xref to the response vtable
    P("")
    P("--- D2-7 vtable 0x180220488 slots + xrefs ---")
    for i in range(8):
        t = qword(0x180220488 + i * 8)
        P("   +0x%02x -> %#x %s" % (i * 8, t, fname(t) if fm.getFunctionAt(addr(t)) else ""))
    P("   xrefs to 0x180220488: %s" % [(hex(x[0]), x[2]) for x in xrefs_to(0x180220488)])
    P("   dec(0x180122420) = %s" % dec(0x180122420).replace("\n", " ")[:300])

    with open(OUT, "w") as fh:
        fh.write("\n".join(lines))
    print("WROTE", OUT)
except Exception:
    traceback.print_exc()
