diff --git a/commands/title/info.py b/commands/title/info.py index d30b8f6..48f336b 100644 --- a/commands/title/info.py +++ b/commands/title/info.py @@ -10,7 +10,10 @@ from modules.core import fatal_error def _print_tmd_info(tmd: libWiiPy.title.TMD): # Get all important keys from the TMD and print them out nicely. print("Title Info") - print(f" Title ID: {tmd.title_id}") + try: + print(f" Title ID: {tmd.title_id.upper()} ({str(bytes.fromhex(tmd.title_id[8:]).decode()).upper()})") + except UnicodeDecodeError: + print(f" Title ID: {tmd.title_id.upper()}") # This type of version number really only applies to the System Menu and IOS. if tmd.title_id[:8] == "00000001": print(f" Title Version: {tmd.title_version} ({tmd.title_version_converted})") @@ -21,7 +24,7 @@ def _print_tmd_info(tmd: libWiiPy.title.TMD): if tmd.ios_tid == "0000000000000000": print(f" Required IOS: N/A") else: - print(f" Required IOS: IOS{int(tmd.ios_tid[-2:], 16)} ({tmd.ios_tid})") + print(f" Required IOS: IOS{int(tmd.ios_tid[-2:], 16)} ({tmd.ios_tid.upper()})") if tmd.signature_issuer.find("CP00000004") != -1: print(f" Certificate: CP00000004 (Retail)") print(f" Certificate Issuer: Root-CA00000001 (Retail)") @@ -45,7 +48,7 @@ def _print_tmd_info(tmd: libWiiPy.title.TMD): region = "KOR" case _: region = "None" - elif tmd.title_id[:8] == "00000001": + elif tmd.get_title_type() == "System": region = "None" else: region = tmd.get_title_region() @@ -71,7 +74,11 @@ def _print_tmd_info(tmd: libWiiPy.title.TMD): def _print_ticket_info(ticket: libWiiPy.title.Ticket): # Get all important keys from the TMD and print them out nicely. print(f"Ticket Info") - print(f" Title ID: {ticket.title_id.decode()}") + try: + print(f" Title ID: {ticket.title_id.decode().upper()} " + f"({str(bytes.fromhex(ticket.title_id.decode()[8:]).decode()).upper()})") + except UnicodeDecodeError: + print(f" Title ID: {ticket.title_id.decode().upper()}") # This type of version number really only applies to the System Menu and IOS. if ticket.title_id.decode()[:8] == "00000001": print(f" Title Version: {ticket.title_version} " diff --git a/commands/title/wad.py b/commands/title/wad.py index ab50ece..1385297 100644 --- a/commands/title/wad.py +++ b/commands/title/wad.py @@ -1,9 +1,11 @@ # "commands/title/wad.py" from WiiPy by NinjaCheetah # https://github.com/NinjaCheetah/WiiPy +import binascii import pathlib from random import randint import libWiiPy + from modules.core import fatal_error @@ -366,3 +368,75 @@ def handle_wad_unpack(args): output_path.joinpath(content_file_name).write_bytes(title.get_content_by_index(content_file, skip_hash)) print("WAD file unpacked!") + + +def handle_wad_edit(args): + input_path = pathlib.Path(args.input) + if args.output is not None: + output_path = pathlib.Path(args.output) + else: + output_path = pathlib.Path(args.input) + + title = libWiiPy.title.Title() + title.load_wad(input_path.read_bytes()) + + # State variable to make sure that changes are made. + edits_made = False + # Go over every possible change, and apply them if they were specified. + if args.tid is not None: + # Setting a new TID, only changing TID low since this expects a 4 character ASCII input. + new_tid = args.tid + if len(new_tid) != 4: + fatal_error(f"The specified Title ID is not valid! The new Title ID should be 4 characters long.") + if not new_tid.isalnum(): + fatal_error(f"The specified Title ID is not valid! The new Title ID should be alphanumeric.") + # Get the current TID high, because we want to preserve the title type while only changing the TID low. + tid_high = title.tmd.title_id[:8] + new_tid = f"{tid_high}{str(binascii.hexlify(new_tid.encode()), 'ascii')}" + title.set_title_id(new_tid) + edits_made = True + if args.ios is not None: + # Setting a new required IOS. + new_ios = None + try: + new_ios = int(args.ios) + except ValueError: + fatal_error("The specified IOS is not valid! The new IOS should be a valid integer.") + if new_ios < 3 or new_ios > 255: + fatal_error("The specified IOS is not valid! The new IOS version should be between 3 and 255.") + new_ios_tid = f"00000001{new_ios:08X}" + title.tmd.ios_tid = new_ios_tid + edits_made = True + if args.type is not None: + # Setting a new title type. + new_type = args.type + new_tid_high = None + match new_type: + case "System": + new_tid_high = "00000001" + case "Channel": + new_tid_high = "00010001" + case "SystemChannel": + new_tid_high = "00010002" + case "GameChannel": + new_tid_high = "00010004" + case "DLC": + new_tid_high = "00010005" + case "HiddenChannel": + new_tid_high = "00010008" + case _: + fatal_error("The specified type is not valid! The new type must be one of: System, Channel, " + "SystemChannel, GameChannel, DLC, HiddenChannel.") + tid_low = title.tmd.title_id[8:] + new_tid = f"{new_tid_high}{tid_low}" + title.set_title_id(new_tid) + edits_made = True + + if not edits_made: + fatal_error("You must specify at least one change to make!") + + # Fakesign the title since any changes have already invalidated the signature. + title.fakesign() + output_path.write_bytes(title.dump_wad()) + + print("Successfully edited WAD file!") diff --git a/wiipy.py b/wiipy.py index 4da891b..e328bcd 100644 --- a/wiipy.py +++ b/wiipy.py @@ -286,6 +286,21 @@ if __name__ == "__main__": "installed from Wii U mode if a Wii U mode WAD installer is created") wad_convert_parser.add_argument("-o", "--output", metavar="OUT", type=str, help="file to output the new WAD to (optional, defaults to '_.wad')") + # Edit WAD subcommand. + wad_edit_parser = wad_subparsers.add_parser("edit", help="edit the properties of a WAD file", + description="edit the properties of a WAD file; by default, this will " + "overwrite the input file unless an output is specified") + wad_edit_parser.set_defaults(func=handle_wad_edit) + wad_edit_parser.add_argument("input", metavar="IN", type=str, help="WAD file to edit") + wad_edit_parser.add_argument("--tid", metavar="TID", type=str, + help="a new Title ID for this WAD (formatted as 4 ASCII characters)") + wad_edit_parser.add_argument("--ios", metavar="IOS", type=str, + help="a new IOS version for this WAD (formatted as the decimal IOS version, eg. 58)") + wad_edit_parser.add_argument("--type", metavar="TYPE", type=str, + help="a new title type for this WAD (valid options: System, Channel, SystemChannel, " + "GameChannel, DLC, HiddenChannel)") + wad_edit_parser.add_argument("-o", "--output", metavar="OUT", type=str, + help="file to output the updated WAD to (optional)") # Pack WAD subcommand. wad_pack_parser = wad_subparsers.add_parser("pack", help="pack a directory to a WAD file", description="pack a directory to a WAD file")