"""Q2: two string clusters that look like family-name tables.

Q1 found 'badge' 0x18022a220, 'kit' 0x18022a228, 'leagueLogo' 0x18022a230,
'ball' 0x18022a278 packed together, and a second cluster 'badge' 0x1802303c8,
'ball' 0x1802303dc, 'equippables' 0x180230f48, 'leagueLogo' 0x180231608.

HYPOTHESIS: cluster 1 is the value list of a {name -> code} enum table like the
itemState one (stride 0x10: char* then int). Cluster 2 is the club?type= route
vocabulary.

CONTROL: the itemState table itself. My Q1 read started mid-table (row0 =
activeBadge with code 0x64, while the doc's list starts at WAITING_FOR_GAME), so
this query re-walks BACKWARDS from 0x180229d20 to find the real table start and
prints it in full. If the ten documented names do not appear in order, my table
walker is wrong.

Then: for every string in each cluster, find the .rdata qword that points at it
(the table row) and print the row's neighbours, plus xrefs.
"""
import traceback


def dump_strings(lo, hi, label):
    print("=== strings %s  %#x..%#x ===" % (label, lo, hi))
    p = lo
    while p < hi:
        try:
            b = mem.getByte(addr(p)) & 0xFF
        except Exception:
            p += 1
            continue
        if 0x20 <= b < 0x7F:
            s = rd_str(p, 96)
            if len(s) >= 2:
                print("  %#x  %r" % (p, s))
            p += max(1, len(s)) + 1
        else:
            p += 1


def walk_table(start, n, back=0):
    print("--- table walk from %#x, %d rows (stride 0x10) ---" % (start, n))
    for i in range(-back, n):
        e = start + i * 0x10
        try:
            q0, q1 = qword(e), qword(e + 8)
        except Exception:
            continue
        s = ""
        if 0x180000000 <= q0 < 0x181000000:
            try:
                s = rd_str(q0, 64)
            except Exception:
                s = "?"
        print("  [%3d] %#x  ptr=%#x %-26r val=%#x" % (i, e, q0, s, q1))


try:
    walk_table(0x180229D20, 8, back=14)
    print()
    dump_strings(0x18022A200, 0x18022A380, "cluster1")
    print()
    dump_strings(0x180230300, 0x180230420, "cluster2a")
    print()
    dump_strings(0x180230F00, 0x180230FA0, "cluster2b")
    print()
    dump_strings(0x180231380, 0x180231680, "cluster2c")
    print()
    print("=== xrefs / pointer-rows for cluster strings ===")
    for name, a in [("badge", 0x18022A220), ("kit", 0x18022A228),
                    ("leagueLogo", 0x18022A230), ("ball", 0x18022A278),
                    ("badge2", 0x1802303C8), ("ball2", 0x1802303DC),
                    ("equippables", 0x180230F48), ("leagueLogo2", 0x180231608),
                    ("itemState", 0x180231490)]:
        print("  %s @%#x" % (name, a))
        for frm, typ, fn, ent in xrefs_to(a):
            print("     xref from %#x %s in %s(%#x)" % (frm, typ, fn, ent))
        ptrs = find_all(a.to_bytes(8, "little"), blocks=(".rdata", ".data"))
        for pa in ptrs[:8]:
            print("     ptr-row @%#x  next-q=%#x prev-q=%#x" %
                  (pa, qword(pa + 8), qword(pa - 8)))
            for frm, typ, fn, ent in xrefs_to(pa):
                print("        row xref %#x %s in %s(%#x)" % (frm, typ, fn, ent))
except Exception:
    traceback.print_exc()
