"""Q22: resolve the manager object's vtable through the global DAT_1802e6398.

FUN_18011a830 just returns DAT_1802e6398, so the vtable is installed wherever that
global is written. Find the writers, decompile the smallest, and read the vtable it
stores. Then dump slots 0x490 / 0x498 / 0xa08 / 0xa38 / 0xa40.

CONTROL: the recovered vtable's slot 0xa08 and 0xa40 must both be real functions
(the item deserializer calls 0xa08 to file an item; FUN_18011e3c0 calls 0xa40 with a
resourceId). If either is not a function, the vtable is wrong.
"""
import traceback

try:
    print("=== writers/readers of DAT_1802e6398 ===")
    ents = {}
    for frm, typ, fn, ent in xrefs_to(0x1802E6398):
        ents.setdefault(ent, []).append((frm, typ, fn))
    for ent, lst in sorted(ents.items()):
        print("  %s(%#x) n=%d types=%s" %
              (lst[0][2], ent, len(lst), sorted({t for _f, t, _n in lst})))
    # the constructor is a function that WRITES it
    writers = [e for e, lst in ents.items()
               if any(t == "WRITE" for _f, t, _n in lst)]
    print("writers: %s" % ["%#x" % w for w in writers])
    for w in writers:
        src = dec(w)
        print("=" * 70)
        print("writer FUN_%x len=%d" % (w, len(src)))
        print(src if len(src) < 6000 else src[:6000] + "\n...[cut]")
except Exception:
    traceback.print_exc()
