from collections.abc import MutableSequence u32_le = lambda i: i.to_bytes(length=4, byteorder='little') class Rating: EC = 0 E = 1 E10 = 2 T = 3 M = 4 AO = 5 RP = 6 class GuideMode: N = 0x11 # nothing B = 0x13 # buttons only T = 0x15 # touch only BT = 0x17 # buttons + touch class Button: START = 0 SELECT = 1 A = 2 B = 3 X = 4 Y = 5 L = 6 R = 7 DPAD = 8 class DemoMenu(MutableSequence): def __init__(self): self.entries: list[DemoMenu.DemoMenuEntry] = [] def encode(self) -> bytes: return b''.join([ u32_le(len(self.entries)), b''.join(entry.encode() for entry in self.entries), u32_le(0) ]) __bytes__ = encode def __getitem__(self, index): return self.entries[index] def __setitem__(self, index, value): self.entries[index] = value def __delitem__(self, index): del self.entries[index] def __len__(self): return len(self.entries) def insert(self, index, value): self.entries.insert(index, value) class DemoMenuEntry: def __init__(self, data: bytes|None = None): if data is None: self.banner_image = bytes(0x200) self.banner_palette = bytes(0x20) self.banner_text = [''] * 2 self.rating = Rating.E self.guide_mode = GuideMode.N self.buttons_text = [''] * 9 self.unknown_text = [''] * 3 self.touch_text = [''] * 2 self.padding = bytes(0x40) self.internal_name = '' return self.banner_image = data[:0x200] self.banner_palette = data[0x200:0x220] self.banner_text = [ data[i:i+0x80].decode('latin-1').rstrip('\0') for i in range(0x220, 0x320, 0x80) ] self.rating = data[0x320] self.guide_mode = data[0x321] self.buttons_text = [ data[i:i+0x20].decode('latin-1').rstrip('\0') for i in range(0x322, 0x442, 0x20) ] self.unknown_text = [ data[i:i+0x20].decode('latin-1').rstrip('\0') for i in range(0x442, 0x4a2, 0x20) ] self.touch_text = [ data[i:i+0x20].decode('latin-1').rstrip('\0') for i in range(0x4a2, 0x4e2, 0x20) ] self.padding = data[0x4e2:0x522] self.internal_name = data[0x522:0x52c].decode('latin-1').rstrip('\0') def encode(self) -> bytes: return b''.join([ self.banner_image, self.banner_palette, b''.join( text.ljust(0x80, '\0').encode('latin-1') for text in self.banner_text ), self.rating.to_bytes(1), self.guide_mode.to_bytes(1), b''.join( text.ljust(0x20, '\0').encode('latin-1') for text in self.buttons_text ), b''.join( text.ljust(0x20, '\0').encode('latin-1') for text in self.unknown_text ), b''.join( text.ljust(0x20, '\0').encode('latin-1') for text in self.touch_text ), self.padding, self.internal_name.ljust(0xa, '\0').encode('latin-1') ]) __bytes__ = encode def __len__(self): return 0x52c