#!/usr/bin/env python3 # -*- coding: utf-8 -*- # 573in1 - Copyright (C) 2022-2024 spicyjpeg # # 573in1 is free software: you can redistribute it and/or modify it under the # terms of the GNU General Public License as published by the Free Software # Foundation, either version 3 of the License, or (at your option) any later # version. # # 573in1 is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR # A PARTICULAR PURPOSE. See the GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along with # 573in1. If not, see . __version__ = "0.4.1" __author__ = "spicyjpeg" import sys from argparse import ArgumentParser, FileType, Namespace from typing import Mapping, TextIO from common.cart import * from common.util import serialNumberToString, hexdumpToFile ## Dump parser _CHIP_NAMES: Mapping[ChipType, str] = { ChipType.NONE: "None", ChipType.X76F041: "Xicor X76F041", ChipType.X76F100: "Xicor X76F100", ChipType.ZS01: "Konami ZS01 (PIC16CE625)" } def printDumpInfo(dump: CartDump, output: TextIO): if dump.flags & DumpFlag.DUMP_SYSTEM_ID_OK: output.write("Digital I/O board:\n") output.write(f" DS2401 ID: {dump.systemID.hex('-')}\n") output.write( f" Serial number: {serialNumberToString(dump.systemID)}\n\n" ) output.write("Security cartridge:\n") output.write(f" Chip type: {_CHIP_NAMES[dump.chipType]}\n") if dump.flags & DumpFlag.DUMP_CART_ID_OK: output.write(f" DS2401 ID: {dump.cartID.hex('-')}\n") if dump.flags & DumpFlag.DUMP_ZS_ID_OK: output.write(f" ZS01 ID: {dump.zsID.hex('-')}\n") if dump.flags & DumpFlag.DUMP_CONFIG_OK: output.write(f" Configuration: {dump.config.hex('-')}\n") output.write("\nEEPROM dump:\n") hexdumpToFile(dump.data, output) output.write("\n") ## Main def createParser() -> ArgumentParser: parser = ArgumentParser( description = \ "Decodes and displays or saves the contents of a QR code cartridge " "dump generated by the tool.", add_help = False ) group = parser.add_argument_group("Tool options") group.add_argument( "-h", "--help", action = "help", help = "Show this help message and exit" ) group = parser.add_argument_group("File paths") group.add_argument( "-i", "--input", type = FileType("rb"), help = "Read dump (.573 file) or QR string from specified path", metavar = "file" ) group.add_argument( "-l", "--log", type = FileType("at"), default = sys.stdout, help = "Log cartridge info to specified file (stdout by default)", metavar = "file" ) group.add_argument( "-e", "--export", type = FileType("wb"), help = "Export binary dump (.573 file) to specified path", metavar = "file" ) group = parser.add_argument_group("Input data") group.add_argument( "data", type = str, nargs = "?", help = "QR string to decode (if -i was not passed)" ) return parser def main(): parser: ArgumentParser = createParser() args: Namespace = parser.parse_args() if args.input: with args.input as file: data: bytes = file.read() try: dump: CartDump = parseCartDump(data) except: dump: CartDump = parseCartQRString(data.decode("ascii")) elif args.data: dump: CartDump = parseCartQRString(args.data) else: parser.error("a dump must be passed on the command line or using -i") if args.log: printDumpInfo(dump, args.log) if args.export: with args.export as file: file.write(dump.serialize()) if __name__ == "__main__": main()