Compare commits
3 commits
f44bb6cce1
...
2e9467c693
Author | SHA1 | Date | |
---|---|---|---|
![]() |
2e9467c693 | ||
![]() |
2b0ba1a362 | ||
![]() |
9852f46be1 |
5 changed files with 120 additions and 1 deletions
13
README.md
13
README.md
|
@ -1,3 +1,14 @@
|
||||||
# ROM-Info
|
# ROM-Info
|
||||||
|
|
||||||
Display ROM info of select ROMs (e.g. NDS, GB/C/A, 3DS)
|
Display ROM info of select ROMs (e.g. NDS, GB/C/A, 3DS)
|
||||||
|
|
||||||
|
|
||||||
|
# Install (Windows - PowerShell)
|
||||||
|
1. python -m venv .venv
|
||||||
|
2. .\\.venv\Scripts\Activate.ps1
|
||||||
|
3. pip install -r requirements.txt
|
||||||
|
|
||||||
|
|
||||||
|
<br /><br />
|
||||||
|
|
||||||
|
Licensed under [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/)
|
32
logger.py
Normal file
32
logger.py
Normal file
|
@ -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')
|
20
main.py
Normal file
20
main.py
Normal file
|
@ -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.')
|
1
requirements.txt
Normal file
1
requirements.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
colorama==0.4.6
|
55
rominfo/nintendo_ds.py
Normal file
55
rominfo/nintendo_ds.py
Normal file
|
@ -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)
|
Loading…
Add table
Reference in a new issue