import struct, sys, os

MEDIA = [
    (0x00000001, "HARD_DISK"), (0x00000002, "DVD_X2"), (0x00000004, "DVD_CD"),
    (0x00000008, "CD"), (0x00000010, "DVD_5_RO"), (0x00000020, "DVD_9_RO"),
    (0x00000040, "DVD_5_RW"), (0x00000080, "DVD_9_RW"), (0x00000100, "DONGLE"),
    (0x00000200, "MEDIA_BOARD"), (0x40000000, "NONSECURE_HARD_DISK"),
    (0x80000000, "NONSECURE_MODE"),
]
REGION = [
    (0x00000001, "North America"), (0x00000002, "Japan"),
    (0x00000004, "Rest of World"), (0x80000000, "Manufacturing"),
]


def flags(val, table):
    out = [n for b, n in table if val & b]
    return ", ".join(out) if out else "(none)"


data = open(sys.argv[1], "rb").read()
assert data[:4] == b"XBEH", data[:4]
base = struct.unpack("<I", data[0x104:0x108])[0]
cert_addr = struct.unpack("<I", data[0x118:0x11C])[0]
entry_enc = struct.unpack("<I", data[0x128:0x12C])[0]
off = cert_addr - base

size, timedate, title_id = struct.unpack("<III", data[off:off+12])
name = data[off+12:off+12+80].decode("utf-16-le").rstrip("\x00")
allowed_media = struct.unpack("<I", data[off+0x9C:off+0xA0])[0]
region = struct.unpack("<I", data[off+0xA0:off+0xA4])[0]
disk_no = struct.unpack("<I", data[off+0xA8:off+0xAC])[0]
version = struct.unpack("<I", data[off+0xAC:off+0xB0])[0]

print("title name    : %s" % name)
print("title id      : %08X  (xemu compat id: %s)"
      % (title_id, format(title_id, "08x")))
print("version       : %d" % version)
print("disk number   : %d" % disk_no)
print("base address  : 0x%08X" % base)
print("allowed media : 0x%08X -> %s" % (allowed_media, flags(allowed_media, MEDIA)))
print("game region   : 0x%08X -> %s" % (region, flags(region, REGION)))
for key, label in ((0xA8FC57AB, "RETAIL"), (0x94859D4B, "DEBUG")):
    ep = entry_enc ^ key
    if 0x10000 <= ep < 0x08000000:
        print("entry point   : 0x%08X (%s build)" % (ep, label))
