mirror of
https://github.com/NinjaCheetah/libWiiPy.git
synced 2025-04-26 05:11:02 -04:00
Added new module for handling sys files, currently supports uid.sys
This commit is contained in:
parent
194b65c6d6
commit
bab777b8b9
@ -5,6 +5,7 @@ from .content import *
|
|||||||
from .crypto import *
|
from .crypto import *
|
||||||
from .iospatcher import *
|
from .iospatcher import *
|
||||||
from .nus import *
|
from .nus import *
|
||||||
|
from .sys import *
|
||||||
from .ticket import *
|
from .ticket import *
|
||||||
from .title import *
|
from .title import *
|
||||||
from .tmd import *
|
from .tmd import *
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
# https://github.com/NinjaCheetah/libWiiPy
|
# https://github.com/NinjaCheetah/libWiiPy
|
||||||
#
|
#
|
||||||
# See https://wiibrew.org/wiki/Title for details about how titles are formatted
|
# See https://wiibrew.org/wiki/Title for details about how titles are formatted
|
||||||
|
|
||||||
import binascii
|
import binascii
|
||||||
import io
|
import io
|
||||||
import hashlib
|
import hashlib
|
||||||
@ -565,7 +566,6 @@ class SharedContentMap:
|
|||||||
str
|
str
|
||||||
The filename assigned to the provided content hash.
|
The filename assigned to the provided content hash.
|
||||||
"""
|
"""
|
||||||
content_hash_converted = b''
|
|
||||||
if type(content_hash) is bytes:
|
if type(content_hash) is bytes:
|
||||||
# This catches the format b'GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG'
|
# This catches the format b'GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG'
|
||||||
if len(content_hash) == 40:
|
if len(content_hash) == 40:
|
||||||
|
124
src/libWiiPy/title/sys.py
Normal file
124
src/libWiiPy/title/sys.py
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
# "title/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.
|
||||||
|
|
||||||
|
import io
|
||||||
|
import binascii
|
||||||
|
from typing import List
|
||||||
|
from dataclasses import dataclass as _dataclass
|
||||||
|
|
||||||
|
|
||||||
|
@_dataclass
|
||||||
|
class _UidSysEntry:
|
||||||
|
"""
|
||||||
|
A _UidSysEntry object used to store an entry in uid.sys. Private class used by the sys module.
|
||||||
|
|
||||||
|
Attributes
|
||||||
|
----------
|
||||||
|
title_id : str
|
||||||
|
The Title ID of the title this entry corresponds with.
|
||||||
|
uid : int
|
||||||
|
The UID assigned to the title this entry corresponds with.
|
||||||
|
"""
|
||||||
|
title_id: str
|
||||||
|
uid: int
|
||||||
|
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
Attributes
|
||||||
|
----------
|
||||||
|
uid_entries : List[_UidSysEntry]
|
||||||
|
The entries stored in the uid.sys file.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.uid_entries: List[_UidSysEntry] = []
|
||||||
|
|
||||||
|
def load(self, uid_sys: bytes) -> None:
|
||||||
|
"""
|
||||||
|
Loads the raw data of uid.sys and parses it into a list of entries.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
uid_sys : bytes
|
||||||
|
The data of a uid.sys file.
|
||||||
|
"""
|
||||||
|
# Sanity check to ensure the length is divisible by 12 bytes. If it isn't, then it is malformed.
|
||||||
|
if (len(uid_sys) % 12) != 0:
|
||||||
|
raise ValueError("The provided uid.sys appears to be corrupted!")
|
||||||
|
entry_count = len(uid_sys) // 12
|
||||||
|
with io.BytesIO(uid_sys) as uid_data:
|
||||||
|
for i in range(entry_count):
|
||||||
|
title_id = binascii.hexlify(uid_data.read(8)).decode()
|
||||||
|
uid_data.seek(uid_data.tell() + 2)
|
||||||
|
uid = int.from_bytes(uid_data.read(2))
|
||||||
|
self.uid_entries.append(_UidSysEntry(title_id, uid))
|
||||||
|
|
||||||
|
def dump(self) -> bytes:
|
||||||
|
"""
|
||||||
|
Dumps the UidSys object back into a uid.sys file.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
bytes
|
||||||
|
The raw data of the uid.sys file.
|
||||||
|
"""
|
||||||
|
uid_data = b''
|
||||||
|
for record in self.uid_entries:
|
||||||
|
uid_data += binascii.unhexlify(record.title_id.encode())
|
||||||
|
uid_data += b'\x00' * 2
|
||||||
|
uid_data += int.to_bytes(record.uid, 2)
|
||||||
|
return uid_data
|
||||||
|
|
||||||
|
def add(self, title_id: str | bytes) -> int:
|
||||||
|
"""
|
||||||
|
Adds a new Title ID to the uid.sys file and returns the UID assigned to that title.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
title_id : str, bytes
|
||||||
|
The Title ID to add.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
int
|
||||||
|
The UID assigned to the new Title ID.
|
||||||
|
"""
|
||||||
|
if type(title_id) is bytes:
|
||||||
|
# This catches the format b'0000000100000002'
|
||||||
|
if len(title_id) == 16:
|
||||||
|
title_id_converted = title_id.encode()
|
||||||
|
# This catches the format b'\x00\x00\x00\x01\x00\x00\x00\x02'
|
||||||
|
elif len(title_id) == 8:
|
||||||
|
title_id_converted = binascii.hexlify(title_id).decode()
|
||||||
|
# If it isn't one of those lengths, it cannot possibly be valid, so reject it.
|
||||||
|
else:
|
||||||
|
raise ValueError("Title ID is not valid!")
|
||||||
|
# Allow for a string like "0000000100000002"
|
||||||
|
elif type(title_id) is str:
|
||||||
|
if len(title_id) != 16:
|
||||||
|
raise ValueError("Title ID is not valid!")
|
||||||
|
title_id_converted = title_id
|
||||||
|
else:
|
||||||
|
raise TypeError("Title ID type is not valid! It must be either type str or bytes.")
|
||||||
|
# Generate the new UID by incrementing the current highest UID by 1.
|
||||||
|
try:
|
||||||
|
new_uid = self.uid_entries[-1].uid + 1
|
||||||
|
except IndexError:
|
||||||
|
new_uid = 4096
|
||||||
|
self.uid_entries.append(_UidSysEntry(title_id_converted, new_uid))
|
||||||
|
return new_uid
|
||||||
|
|
||||||
|
def create(self) -> None:
|
||||||
|
"""
|
||||||
|
Creates a new uid.sys file and initializes it with the standard first entry of 1-2 with UID 4096. This allows
|
||||||
|
for setting up a uid.sys file without having to load an existing one.
|
||||||
|
"""
|
||||||
|
if len(self.uid_entries) != 0:
|
||||||
|
raise Exception("A uid.sys file appears to already exist!")
|
||||||
|
self.add("0000000100000002")
|
Loading…
x
Reference in New Issue
Block a user