mirror of
				https://github.com/NinjaCheetah/libWiiPy.git
				synced 2025-10-30 23:26:19 -04:00 
			
		
		
		
	Added setting.txt parser, moved some modules under a new "nand" subpackage
This commit is contained in:
		
							parent
							
								
									1ae649afac
								
							
						
					
					
						commit
						9fb0fdbc17
					
				| @ -6,6 +6,7 @@ | ||||
| :maxdepth: 4 | ||||
| 
 | ||||
| libWiiPy.archive | ||||
| libWiiPy.nand | ||||
| libWiiPy.title | ||||
| ``` | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										27
									
								
								docs/source/libWiiPy.nand.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								docs/source/libWiiPy.nand.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,27 @@ | ||||
| # libWiiPy.nand package | ||||
| 
 | ||||
| ## Submodules | ||||
| 
 | ||||
| ### libWiiPy.nand.emunand module | ||||
| ```{eval-rst} | ||||
| .. automodule:: libWiiPy.nand.emunand | ||||
|    :members: | ||||
|    :undoc-members: | ||||
|    :show-inheritance: | ||||
| ``` | ||||
| 
 | ||||
| ### libWiiPy.nand.setting module | ||||
| ```{eval-rst} | ||||
| .. automodule:: libWiiPy.nand.setting | ||||
|    :members: | ||||
|    :undoc-members: | ||||
|    :show-inheritance: | ||||
| ``` | ||||
| 
 | ||||
| ### libWiiPy.nand.sys module | ||||
| ```{eval-rst} | ||||
| .. automodule:: libWiiPy.nand.sys | ||||
|    :members: | ||||
|    :undoc-members: | ||||
|    :show-inheritance: | ||||
| ``` | ||||
| @ -26,14 +26,6 @@ | ||||
|    :show-inheritance: | ||||
| ``` | ||||
| 
 | ||||
| ### libWiiPy.title.emunand module | ||||
| ```{eval-rst} | ||||
| .. automodule:: libWiiPy.title.emunand | ||||
|    :members: | ||||
|    :undoc-members: | ||||
|    :show-inheritance: | ||||
| ``` | ||||
| 
 | ||||
| ### libWiipy.title.iospatcher module | ||||
| ```{eval-rst} | ||||
| .. automodule:: libWiiPy.title.iospatcher | ||||
| @ -50,14 +42,6 @@ | ||||
|    :show-inheritance: | ||||
| ``` | ||||
| 
 | ||||
| ### libWiiPy.title.sys module | ||||
| ```{eval-rst} | ||||
| .. automodule:: libWiiPy.title.sys | ||||
|    :members: | ||||
|    :undoc-members: | ||||
|    :show-inheritance: | ||||
| ``` | ||||
| 
 | ||||
| ### libWiiPy.title.ticket module | ||||
| ```{eval-rst} | ||||
| .. automodule:: libWiiPy.title.ticket | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| [project] | ||||
| name = "libWiiPy" | ||||
| version = "0.5.0" | ||||
| version = "0.5.1" | ||||
| authors = [ | ||||
|     { name="NinjaCheetah", email="ninjacheetah@ncxprogramming.com" }, | ||||
|     { name="Lillian Skinner", email="lillian@randommeaninglesscharacters.com" } | ||||
|  | ||||
| @ -3,7 +3,8 @@ | ||||
| # | ||||
| # These are the essential submodules from libWiiPy that you'd probably want imported by default. | ||||
| 
 | ||||
| __all__ = ["archive", "title"] | ||||
| __all__ = ["archive", "nand", "title"] | ||||
| 
 | ||||
| from . import archive | ||||
| from . import nand | ||||
| from . import title | ||||
|  | ||||
							
								
								
									
										6
									
								
								src/libWiiPy/nand/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/libWiiPy/nand/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | ||||
| # "nand/__init__.py" from libWiiPy by NinjaCheetah & Contributors | ||||
| # https://github.com/NinjaCheetah/libWiiPy | ||||
| 
 | ||||
| from .emunand import * | ||||
| from .setting import * | ||||
| from .sys import * | ||||
| @ -1,4 +1,4 @@ | ||||
| # "title/emunand.py" from libWiiPy by NinjaCheetah & Contributors | ||||
| # "nand/emunand.py" from libWiiPy by NinjaCheetah & Contributors | ||||
| # https://github.com/NinjaCheetah/libWiiPy | ||||
| # | ||||
| # Code for handling setting up and modifying a Wii EmuNAND. | ||||
| @ -6,8 +6,8 @@ | ||||
| import os | ||||
| import pathlib | ||||
| import shutil | ||||
| from .title import Title | ||||
| from .content import SharedContentMap as _SharedContentMap | ||||
| from ..title.title import Title | ||||
| from ..title.content import SharedContentMap as _SharedContentMap | ||||
| from .sys import UidSys as _UidSys | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										135
									
								
								src/libWiiPy/nand/setting.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								src/libWiiPy/nand/setting.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,135 @@ | ||||
| # "nand/setting.py" from libWiiPy by NinjaCheetah & Contributors | ||||
| # https://github.com/NinjaCheetah/libWiiPy | ||||
| # | ||||
| # See https://wiibrew.org/wiki//title/00000001/00000002/data/setting.txt for information about setting.txt. | ||||
| 
 | ||||
| import io | ||||
| from ..shared import _pad_bytes | ||||
| 
 | ||||
| 
 | ||||
| _key = 0x73B5DBFA | ||||
| 
 | ||||
| class SettingTxt: | ||||
|     """ | ||||
|     A SettingTxt object that allows for decrypting and then parsing a setting.txt file from the Wii. | ||||
| 
 | ||||
|     Attributes | ||||
|     ---------- | ||||
|     area : str | ||||
|         The region of the System Menu this file matches with. | ||||
|     model : str | ||||
|         The model of the console, usually RVL-001 or RVL-101. | ||||
|     dvd : int | ||||
|         Unknown, might have to do with indicating support for scrapped DVD playback capabilities. | ||||
|     mpch : str | ||||
|         Unknown, generally accepted value is "0x7FFE". | ||||
|     code : str | ||||
|         Unknown code, may match with manufacturer code in serial number? | ||||
|     serial_number : str | ||||
|         Serial number of the console. | ||||
|     video : str | ||||
|         Video mode, either NTSC or PAL. | ||||
|     game : str | ||||
|         Another region code, possibly set by the hidden region select channel. | ||||
|     """ | ||||
|     def __init__(self): | ||||
|         self.area: str = "" | ||||
|         self.model: str = "" | ||||
|         self.dvd: int = 0 | ||||
|         self.mpch: str = ""  # What does this mean, Movie Player Channel? It's also a hex string, it seems. | ||||
|         self.code: str = "" | ||||
|         self.serial_number: str = "" | ||||
|         self.video: str = "" | ||||
|         self.game: str = "" | ||||
| 
 | ||||
|     def load(self, setting_txt: bytes) -> None: | ||||
|         """ | ||||
|         Loads the raw data of an encrypted setting.txt file and decrypts it to parse its arguments | ||||
| 
 | ||||
|         Parameters | ||||
|         ---------- | ||||
|         setting_txt : bytes | ||||
|             The data of an encrypted setting.txt file. | ||||
|         """ | ||||
|         with io.BytesIO(setting_txt) as setting_data: | ||||
|             global _key  # I still don't actually know what *kind* of encryption this is. | ||||
|             setting_txt_dec: [int] = [] | ||||
|             for i in range(0, 256): | ||||
|                 setting_txt_dec.append(int.from_bytes(setting_data.read(1)) ^ (_key & 0xff)) | ||||
|                 _key = (_key << 1) | (_key >> 31) | ||||
|         setting_txt_dec = bytes(setting_txt_dec) | ||||
|         try: | ||||
|             setting_str = setting_txt_dec.decode('utf-8') | ||||
|         except UnicodeDecodeError: | ||||
|             last_newline_pos = setting_txt_dec.rfind(b'\n')  # This makes sure we don't try to decode any garbage data. | ||||
|             setting_str = setting_txt_dec[:last_newline_pos + 1].decode('utf-8') | ||||
|         self.load_decrypted(setting_str) | ||||
| 
 | ||||
|     def load_decrypted(self, setting_txt: str) -> None: | ||||
|         """ | ||||
|         Loads the raw data of a decrypted setting.txt file and parses its arguments | ||||
| 
 | ||||
|         Parameters | ||||
|         ---------- | ||||
|         setting_txt : str | ||||
|             The data of a decrypted setting.txt file. | ||||
|         """ | ||||
|         setting_dict = {} | ||||
|         print(setting_txt) | ||||
|         # Iterate over every key in the file to create a dictionary. | ||||
|         for line in setting_txt.splitlines(): | ||||
|             line = line.strip() | ||||
|             if line is not None: | ||||
|                 key, value = line.split('=', 1) | ||||
|                 setting_dict[key.strip()] = value.strip() | ||||
|         # Load the values from the dictionary into the object. | ||||
|         self.area = setting_dict["AREA"] | ||||
|         self.model = setting_dict["MODEL"] | ||||
|         self.dvd = int(setting_dict["DVD"]) | ||||
|         self.mpch = setting_dict["MPCH"] | ||||
|         self.code = setting_dict["CODE"] | ||||
|         self.serial_number = setting_dict["SERNO"] | ||||
|         self.video = setting_dict["VIDEO"] | ||||
|         self.game = setting_dict["GAME"] | ||||
| 
 | ||||
|     def dump(self) -> bytes: | ||||
|         """ | ||||
|         Dumps the SettingTxt object back into an encrypted bytes that the Wii can load. | ||||
| 
 | ||||
|         Returns | ||||
|         ------- | ||||
|         bytes | ||||
|             The setting.txt file as encrypted bytes. | ||||
|         """ | ||||
|         setting_str = self.dump_decrypted() | ||||
|         setting_txt_dec = setting_str.encode() | ||||
|         global _key | ||||
|         # This could probably be made more efficient somehow. | ||||
|         setting_txt_enc: [int] = [] | ||||
|         with io.BytesIO(setting_txt_dec) as setting_data: | ||||
|             for i in range(0, len(setting_txt_dec)): | ||||
|                 setting_txt_enc.append(int.from_bytes(setting_data.read(1)) ^ (_key & 0xff)) | ||||
|                 _key = (_key << 1) | (_key >> 31) | ||||
|         setting_txt_enc = _pad_bytes(bytes(setting_txt_enc), 256) | ||||
|         return setting_txt_enc | ||||
| 
 | ||||
|     def dump_decrypted(self) -> str: | ||||
|         """ | ||||
|         Dumps the SettingTxt object into a decrypted string. | ||||
| 
 | ||||
|         Returns | ||||
|         ------- | ||||
|         str | ||||
|             The setting.txt file as decrypted text. | ||||
|         """ | ||||
|         # Write the keys back into a text file that can then be manually edited or re-encrypted. | ||||
|         setting_txt = "" | ||||
|         setting_txt += f"AREA={self.area}\n" | ||||
|         setting_txt += f"MODEL={self.model}\n" | ||||
|         setting_txt += f"DVD={self.dvd}\n" | ||||
|         setting_txt += f"MPCH={self.mpch}\n" | ||||
|         setting_txt += f"CODE={self.code}\n" | ||||
|         setting_txt += f"SERNO={self.serial_number}\n" | ||||
|         setting_txt += f"VIDEO={self.video}\n" | ||||
|         setting_txt += f"GAME={self.game}\n" | ||||
|         return setting_txt | ||||
| @ -1,4 +1,4 @@ | ||||
| # "title/sys.py" from libWiiPy by NinjaCheetah & Contributors | ||||
| # "nand/sys.py" from libWiiPy by NinjaCheetah & Contributors | ||||
| # https://github.com/NinjaCheetah/libWiiPy | ||||
| # | ||||
| # See https://wiibrew.org/wiki//sys/uid.sys for information about uid.sys. | ||||
| @ -28,7 +28,7 @@ class _UidSysEntry: | ||||
| class UidSys: | ||||
|     """ | ||||
|     A UidSys object to parse and edit the uid.sys file stored in /sys/ on the Wii's NAND. This file is used to track all | ||||
|     the titles installed on the console. | ||||
|     the titles that have been launched on a console. | ||||
| 
 | ||||
|     Attributes | ||||
|     ---------- | ||||
| @ -3,10 +3,8 @@ | ||||
| 
 | ||||
| from .content import * | ||||
| from .crypto import * | ||||
| from .emunand import * | ||||
| from .iospatcher import * | ||||
| from .nus import * | ||||
| from .sys import * | ||||
| from .ticket import * | ||||
| from .title import * | ||||
| from .tmd import * | ||||
|  | ||||
| @ -37,7 +37,7 @@ class TMD: | ||||
|         self.blob_header: bytes = b'' | ||||
|         self.signature_type: int = 0 | ||||
|         self.signature: bytes = b'' | ||||
|         self.issuer: bytes = b''  # Follows the format "Root-CA%08x-CP%08x" | ||||
|         self.signature_issuer: str = ""  # Follows the format "Root-CA%08x-CP%08x" | ||||
|         self.tmd_version: int = 0  # This seems to always be 0 no matter what? | ||||
|         self.ca_crl_version: int = 0  # Certificate Authority Certificate Revocation List version | ||||
|         self.signer_crl_version: int = 0  # Certificate Policy Certificate Revocation List version | ||||
| @ -82,7 +82,7 @@ class TMD: | ||||
|             self.signature = tmd_data.read(256) | ||||
|             # Signing certificate issuer. | ||||
|             tmd_data.seek(0x140) | ||||
|             self.issuer = tmd_data.read(64) | ||||
|             self.signature_issuer = str(tmd_data.read(64).decode()) | ||||
|             # TMD version, seems to usually be 0, but I've seen references to other numbers. | ||||
|             tmd_data.seek(0x180) | ||||
|             self.tmd_version = int.from_bytes(tmd_data.read(1)) | ||||
| @ -175,7 +175,7 @@ class TMD: | ||||
|         # Padding to 64 bytes. | ||||
|         tmd_data += b'\x00' * 60 | ||||
|         # Signing certificate issuer. | ||||
|         tmd_data += self.issuer | ||||
|         tmd_data += str.encode(self.signature_issuer) | ||||
|         # TMD version. | ||||
|         tmd_data += int.to_bytes(self.tmd_version, 1) | ||||
|         # Certificate Authority CRL version. | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user