class PSPTool: @classmethod def from_file(cls, filename, verbose=False): with open(filename, 'rb') as f: rom_bytes = bytearray(f.read()) pt = PSPTool(rom_bytes, verbose=verbose) pt.filename = filename return pt def __init__(self, rom_bytes, verbose=False): self.print_warning = print_warning if verbose else lambda *args, **kwargs: None self.blob = Blob(rom_bytes, len(rom_bytes), self) self.filename = None def __repr__(self): if self.filename is not None: return f'PSPTool(filename={self.filename})' else: return f'PSPTool(len(rom_bytes)={self.blob.buffer_size}' def to_file(self, filename): with open(filename, 'wb') as f: f.write(self.blob.get_buffer()) def ls(self, verbose=False): for index, directory in enumerate(self.blob.directories): t = PrettyTable( ['Directory', 'Addr', 'Type', 'Magic', 'Secondary Directory']) t.add_row([ index, hex(directory.get_address()), directory.type, directory.magic.decode('utf-8', 'backslashreplace'), hex(directory.secondary_directory_address) if directory.secondary_directory_address else '--' ]) print(t) self.ls_dir(index, verbose=verbose) print('\n') def ls_dir(self, directory_index, verbose=False): directory = self.blob.directories[directory_index] self.ls_entries(entries=directory.entries, verbose=verbose) def ls_entries(self, entries=None, verbose=False): # list all entries of all directories by default (sorted by their address) if entries is None: entries = sorted(self.blob.unique_entries) basic_fields = [ ' ', 'Entry', 'Address', 'Size', 'Type', 'Magic/ID', 'Version', 'Info' ] verbose_fields = ['size_signed', 'size_full', 'size_packed'] t = PrettyTable(basic_fields + verbose_fields) t.align = 'r' for index, entry in enumerate(entries): info = [] if entry.compressed: info.append('compressed') if entry.signed: info.append('signed(%s)' % entry.get_readable_signed_by()) if entry.verify_signature(): info.append('verified') if entry.encrypted: info.append('encrypted') all_values = [ '', index, hex(entry.get_address()), hex(entry.buffer_size), entry.get_readable_type(), entry.get_readable_magic(), entry.get_readable_version(), ', '.join(info) ] if type(entry) is HeaderEntry: all_values += [ hex(v) for v in [entry.size_signed, entry.size_full, entry.size_packed] ] else: all_values += (3 * ['']) t.add_row(all_values) fields = basic_fields if verbose is True: fields += verbose_fields print(t.get_string(fields=fields))