def __init__(self, rom: NintendoDSRom): self.rom = rom data = rom.iconBanner self.version = read_u16(data, 0x0) assert len(data) == ICON_BANNER_SIZE assert self.version == 1 # EoS should always use version 1 self.checksum = read_u16(data, 0x2) self.icon = Icon(read_bytes(data, 0x20, 0x200), read_bytes(data, 0x220, 0x20)) self.title_japanese = read_bytes( data, 0x240, 0x100).decode('UTF-16LE').rstrip('\x00') self.title_english = read_bytes( data, 0x340, 0x100).decode('UTF-16LE').rstrip('\x00') self.title_french = read_bytes(data, 0x440, 0x100).decode('UTF-16LE').rstrip('\x00') self.title_german = read_bytes(data, 0x540, 0x100).decode('UTF-16LE').rstrip('\x00') self.title_italian = read_bytes( data, 0x640, 0x100).decode('UTF-16LE').rstrip('\x00') self.title_spanish = read_bytes( data, 0x740, 0x100).decode('UTF-16LE').rstrip('\x00')
def _look_ahead_two_int_sequence(self): seq = bytearray(NRL_LOOKAHEAD_COPY_BYTES_MAX_BYTES * 4) seq_len = 0 # If the repeat counter reaches NRL_MIN_SEQ_LEN, the sequence ends NRL_MIN_SEQ_LEN entries before that repeat_counter = 0 previous_ints_at_pos = 0x1000000 # Impossible "null" value for now nc = self.cursor while True: ints_at_pos = read_bytes(self.uncompressed_data, nc, 4) if ints_at_pos == previous_ints_at_pos: repeat_counter += 1 else: repeat_counter = 0 previous_ints_at_pos = ints_at_pos seq[seq_len * 4:(seq_len * 4) + 4] = ints_at_pos if repeat_counter > NRL_MIN_SEQ_LEN: seq_len -= NRL_MIN_SEQ_LEN break if seq_len + 1 >= NRL_LOOKAHEAD_COPY_BYTES_MAX_BYTES or nc >= self.length_input: break seq_len += 1 nc += 4 return seq_len, seq[:seq_len * 4]
def _read(self) -> bytes: """Reads 4 bytes and increases cursor""" if self.cursor + 4 > self.length_input: raise ValueError("BMA Layer NRL Compressor: Reached EOF while reading data.") oc = self.cursor self.cursor += 4 return read_bytes(self.uncompressed_data, oc, 4)
def _look_ahead_repeats(self, data: bytes): """Look how often the 4 byte pattern in the input data repeats, up to NRL_LOOKAHEAD_MAX_BYTES""" nc = self.cursor repeats = 0 while read_bytes(self.uncompressed_data, nc, 4) == data and \ repeats < NRL_LOOKAHEAD_ZERO_MAX_BYTES and \ nc < self.length_input: repeats += 1 nc += 4 return repeats
def matches(cls, data: bytes, byte_offset=0): """Check if the given data stream is a At3px container""" return read_bytes(data, byte_offset, 5) == b'AT3PX'
def matches(cls, data: bytes, byte_offset=0): """Check if the given data is a At4pn container""" return read_bytes(data, byte_offset, 5) == b'AT4PN'
def matches(cls, data: bytes, byte_offset=0): """Check if the given data stream has the magic string for MD files.""" return read_bytes(data, byte_offset, 4) == b'MD\0\0'
def matches(cls, data: bytes, byte_offset: int = 0) -> bool: """Check if the given data is a container of its type""" return read_bytes(data, byte_offset, len(cls.magic_word())) == cls.magic_word()
def matches(cls, data: bytes, byte_offset=0): """Check if the given data stream is a Sir0 container""" return read_bytes(data, byte_offset, 4) == b'SIR0'