diff --git a/logger.py b/logger.py new file mode 100644 index 0000000..f7a6a4a --- /dev/null +++ b/logger.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- + +from datetime import datetime + +import colorama + + +class Logger(object): + def __init__(self, module: str, datefmt: str = '%m/%d/%Y %I:%M:%S %p'): + colorama.init() + self.module = module + self.datefmt = datefmt + + def info(self, msg: str, levelname: str = 'INFO'): + asctime = datetime.now().strftime(self.datefmt) + + print(f'\033[92m[{asctime}] - {levelname} - {self.module} - {msg}\033[39m') + + def debug(self, msg: str, levelname: str = 'DEBUG'): + asctime = datetime.now().strftime(self.datefmt) + + print(f'\033[93m[{asctime}] - {levelname} - {self.module} - {msg}\033[39m') + + def verbose(self, msg: str, levelname: str = 'VERBOSE'): + asctime = datetime.now().strftime(self.datefmt) + + print(f'\033[96m[{asctime}] - {levelname} - {self.module} - {msg}\033[39m') + + def error(self, msg: str, levelname: str = 'ERROR'): + asctime = datetime.now().strftime(self.datefmt) + + print(f'\033[91m[{asctime}] - {levelname} - {self.module} - {msg}\033[39m') diff --git a/main.py b/main.py new file mode 100644 index 0000000..ced411e --- /dev/null +++ b/main.py @@ -0,0 +1,20 @@ +import sys + +from logger import Logger +from rominfo.nintendo_ds import * + +logger = Logger('RomInfo') + +if __name__ == '__main__': + if len(sys.argv) == 2: + # NDS(i) - https://dsibrew.org/wiki/DSi_cartridge_header + if sys.argv[1].endswith('.nds'): + with open(sys.argv[1], mode='rb') as nds: + logger.info('Title : {}'.format(nds_get_info('title', nds))) + logger.info('Game code : {}'.format(nds_get_info('gamecode', nds))) + logger.info('Maker code : {}'.format(nds_get_info('makercode', nds))) + logger.info('Unit code : {}'.format(nds_get_info('unitcode', nds))) + logger.info('Encryption seed : {}'.format(nds_get_info('encryptionseed', nds))) + logger.info('Device capacity : {}'.format(nds_get_info('devicecapacity', nds))) + else: + logger.error('No ROM specified. App requires one argument.') diff --git a/rominfo/nintendo_ds.py b/rominfo/nintendo_ds.py new file mode 100644 index 0000000..d225bcc --- /dev/null +++ b/rominfo/nintendo_ds.py @@ -0,0 +1,55 @@ +from math import pow +from typing import BinaryIO + + +def nds_get_info(opt: str, inf: BinaryIO): + match opt.lower(): + case 'title': + inf.seek(0x000) + return inf.read(12).decode() + case 'gamecode': + inf.seek(0x00C) + return inf.read(4).decode() + case 'makercode': + inf.seek(0x010) + return _maker_lookup(inf.read(2).decode()) + case 'unitcode': + inf.seek(0x012) + return _unit_lookup(inf.read(1)) + case 'encryptionseed': + inf.seek(0x013) + return str(int.from_bytes(inf.read(1), 'little')) + case 'devicecapacity': + inf.seek(0x014) + return _capacity_lookup(int.from_bytes(inf.read(1), 'little')) + case _: + return 'Unknown' + + +def _maker_lookup(code: str) -> str: + match code: + case '01': + return 'Nintendo ({})'.format(code) + case 'GD': + return 'Square-Enix ({})'.format(code) + case _: + return 'Unknown ({})'.format(code) + + +def _unit_lookup(code: bytes) -> str: + if code == b'\x00': + return 'NDS (00h)' + elif code == b'\x02': + return 'DSi Enhanced (02h)' + elif code == b'\x03': + return 'DSi Exclusive (03h)' + else: + return 'Unknown ({})'.format(code) + + +def _capacity_lookup(code: int) -> str: # 512Mbit (67108864 bytes) (09h) + match code: + case 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12: + return '{} MB ({})'.format(round(128 * pow(2, code) / 1024), '{}h'.format(str(code).zfill(2))) + case _: + return 'Unknown ({})'.format(code)