mirror of
https://github.com/NinjaCheetah/libWiiPy.git
synced 2025-04-26 13:21:01 -04:00
Improved docstrings and made them all much more consistent across the project
This commit is contained in:
parent
7c631454a1
commit
e85eae567a
@ -1,5 +1,7 @@
|
|||||||
# "__init__.py" from libWiiPy by NinjaCheetah & Contributors
|
# "__init__.py" from libWiiPy by NinjaCheetah & Contributors
|
||||||
# https://github.com/NinjaCheetah/libWiiPy
|
# https://github.com/NinjaCheetah/libWiiPy
|
||||||
|
#
|
||||||
|
# These are the essential modules from libWiiPy that you'd probably want imported by default.
|
||||||
|
|
||||||
from .commonkeys import *
|
from .commonkeys import *
|
||||||
from .content import *
|
from .content import *
|
||||||
|
@ -8,8 +8,9 @@ korean_key = '63b82bb4f4614e2e13f2fefbba4c9b7e'
|
|||||||
vwii_key = '30bfc76e7c19afbb23163330ced7c28d'
|
vwii_key = '30bfc76e7c19afbb23163330ced7c28d'
|
||||||
|
|
||||||
|
|
||||||
def get_common_key(common_key_index):
|
def get_common_key(common_key_index) -> bytes:
|
||||||
"""Gets the specified Wii Common Key based on the index provided.
|
"""
|
||||||
|
Gets the specified Wii Common Key based on the index provided.
|
||||||
|
|
||||||
Possible values for common_key_index: 0: Common Key, 1: Korean Key, 2: vWii Key
|
Possible values for common_key_index: 0: Common Key, 1: Korean Key, 2: vWii Key
|
||||||
|
|
||||||
|
@ -12,7 +12,16 @@ from .crypto import decrypt_content, encrypt_content
|
|||||||
|
|
||||||
|
|
||||||
class ContentRegion:
|
class ContentRegion:
|
||||||
"""Creates a ContentRegion object to parse the continuous content region of a WAD.
|
"""
|
||||||
|
A ContentRegion object to parse the continuous content region of a WAD. Allows for retrieving content from the
|
||||||
|
region in both encrypted or decrypted form, and setting new content.
|
||||||
|
|
||||||
|
Attributes
|
||||||
|
----------
|
||||||
|
content_records : List[ContentRecord]
|
||||||
|
The content records for the content stored in the region.
|
||||||
|
num_contents : int
|
||||||
|
The total number of contents stored in the region.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@ -23,7 +32,8 @@ class ContentRegion:
|
|||||||
self.content_list: List[bytes] = []
|
self.content_list: List[bytes] = []
|
||||||
|
|
||||||
def load(self, content_region: bytes, content_records: List[ContentRecord]) -> None:
|
def load(self, content_region: bytes, content_records: List[ContentRecord]) -> None:
|
||||||
"""Loads the raw content region and builds a list of all the contents.
|
"""
|
||||||
|
Loads the raw content region and builds a list of all the contents.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
@ -59,7 +69,8 @@ class ContentRegion:
|
|||||||
self.content_list.append(content_enc)
|
self.content_list.append(content_enc)
|
||||||
|
|
||||||
def dump(self) -> bytes:
|
def dump(self) -> bytes:
|
||||||
"""Takes the list of contents and assembles them back into one content region. Returns this content region as a
|
"""
|
||||||
|
Takes the list of contents and assembles them back into one content region. Returns this content region as a
|
||||||
bytes object and sets the raw content region variable to this result, then calls load() again to make sure the
|
bytes object and sets the raw content region variable to this result, then calls load() again to make sure the
|
||||||
content list matches the raw data.
|
content list matches the raw data.
|
||||||
|
|
||||||
@ -85,7 +96,8 @@ class ContentRegion:
|
|||||||
return content_region_raw
|
return content_region_raw
|
||||||
|
|
||||||
def get_enc_content_by_index(self, index: int) -> bytes:
|
def get_enc_content_by_index(self, index: int) -> bytes:
|
||||||
"""Gets an individual content from the content region based on the provided index, in encrypted form.
|
"""
|
||||||
|
Gets an individual content from the content region based on the provided index, in encrypted form.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
@ -101,7 +113,8 @@ class ContentRegion:
|
|||||||
return content_enc
|
return content_enc
|
||||||
|
|
||||||
def get_enc_content_by_cid(self, cid: int) -> bytes:
|
def get_enc_content_by_cid(self, cid: int) -> bytes:
|
||||||
"""Gets an individual content from the content region based on the provided Content ID, in encrypted form.
|
"""
|
||||||
|
Gets an individual content from the content region based on the provided Content ID, in encrypted form.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
@ -127,7 +140,8 @@ class ContentRegion:
|
|||||||
return content_enc
|
return content_enc
|
||||||
|
|
||||||
def get_enc_contents(self) -> List[bytes]:
|
def get_enc_contents(self) -> List[bytes]:
|
||||||
"""Gets a list of all encrypted contents from the content region.
|
"""
|
||||||
|
Gets a list of all encrypted contents from the content region.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
@ -137,7 +151,8 @@ class ContentRegion:
|
|||||||
return self.content_list
|
return self.content_list
|
||||||
|
|
||||||
def get_content_by_index(self, index: int, title_key: bytes) -> bytes:
|
def get_content_by_index(self, index: int, title_key: bytes) -> bytes:
|
||||||
"""Gets an individual content from the content region based on the provided index, in decrypted form.
|
"""
|
||||||
|
Gets an individual content from the content region based on the provided index, in decrypted form.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
@ -168,7 +183,8 @@ class ContentRegion:
|
|||||||
return content_dec
|
return content_dec
|
||||||
|
|
||||||
def get_content_by_cid(self, cid: int, title_key: bytes) -> bytes:
|
def get_content_by_cid(self, cid: int, title_key: bytes) -> bytes:
|
||||||
"""Gets an individual content from the content region based on the provided Content ID, in decrypted form.
|
"""
|
||||||
|
Gets an individual content from the content region based on the provided Content ID, in decrypted form.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
@ -196,7 +212,8 @@ class ContentRegion:
|
|||||||
return content_dec
|
return content_dec
|
||||||
|
|
||||||
def get_contents(self, title_key: bytes) -> List[bytes]:
|
def get_contents(self, title_key: bytes) -> List[bytes]:
|
||||||
"""Gets a list of all contents from the content region, in decrypted form.
|
"""
|
||||||
|
Gets a list of all contents from the content region, in decrypted form.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
@ -216,7 +233,8 @@ class ContentRegion:
|
|||||||
|
|
||||||
def set_enc_content(self, enc_content: bytes, cid: int, index: int, content_type: int, content_size: int,
|
def set_enc_content(self, enc_content: bytes, cid: int, index: int, content_type: int, content_size: int,
|
||||||
content_hash: bytes) -> None:
|
content_hash: bytes) -> None:
|
||||||
"""Sets the provided index to a new content with the provided Content ID. Hashes and size of the content are
|
"""
|
||||||
|
Sets the provided index to a new content with the provided Content ID. Hashes and size of the content are
|
||||||
set in the content record, with a new record being added if necessary.
|
set in the content record, with a new record being added if necessary.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
@ -257,8 +275,9 @@ class ContentRegion:
|
|||||||
self.content_list[index] = enc_content
|
self.content_list[index] = enc_content
|
||||||
|
|
||||||
def set_content(self, dec_content: bytes, cid: int, index: int, content_type: int, title_key: bytes) -> None:
|
def set_content(self, dec_content: bytes, cid: int, index: int, content_type: int, title_key: bytes) -> None:
|
||||||
"""Sets the provided index to a new content with the provided Content ID. Hashes and size of the content are
|
"""
|
||||||
set in the content record, with a new record being added if necessary.
|
Sets the provided index to a new content with the provided Content ID. Hashes and size of the content are
|
||||||
|
set in the content record, with a new record being added if necessary.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
@ -283,7 +302,8 @@ class ContentRegion:
|
|||||||
self.set_enc_content(enc_content, cid, index, content_type, dec_content_size, dec_content_hash)
|
self.set_enc_content(enc_content, cid, index, content_type, dec_content_size, dec_content_hash)
|
||||||
|
|
||||||
def load_enc_content(self, enc_content: bytes, index: int) -> None:
|
def load_enc_content(self, enc_content: bytes, index: int) -> None:
|
||||||
"""Loads the provided encrypted content into the content region at the specified index, with the assumption that
|
"""
|
||||||
|
Loads the provided encrypted content into the content region at the specified index, with the assumption that
|
||||||
it matches the record at that index. Not recommended for most use cases, use decrypted content and
|
it matches the record at that index. Not recommended for most use cases, use decrypted content and
|
||||||
load_content() instead.
|
load_content() instead.
|
||||||
|
|
||||||
@ -303,7 +323,8 @@ class ContentRegion:
|
|||||||
self.content_list[index] = enc_content
|
self.content_list[index] = enc_content
|
||||||
|
|
||||||
def load_content(self, dec_content: bytes, index: int, title_key: bytes) -> None:
|
def load_content(self, dec_content: bytes, index: int, title_key: bytes) -> None:
|
||||||
"""Loads the provided decrypted content into the content region at the specified index, but first checks to make
|
"""
|
||||||
|
Loads the provided decrypted content into the content region at the specified index, but first checks to make
|
||||||
sure it matches the record at that index before loading. This content will be encrypted when loaded.
|
sure it matches the record at that index before loading. This content will be encrypted when loaded.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
|
@ -7,7 +7,8 @@ from Crypto.Cipher import AES
|
|||||||
|
|
||||||
|
|
||||||
def decrypt_title_key(title_key_enc, common_key_index, title_id) -> bytes:
|
def decrypt_title_key(title_key_enc, common_key_index, title_id) -> bytes:
|
||||||
"""Gets the decrypted version of the encrypted Title Key provided.
|
"""
|
||||||
|
Gets the decrypted version of the encrypted Title Key provided.
|
||||||
|
|
||||||
Requires the index of the common key to use, and the Title ID of the title that the Title Key is for.
|
Requires the index of the common key to use, and the Title ID of the title that the Title Key is for.
|
||||||
|
|
||||||
@ -37,7 +38,8 @@ def decrypt_title_key(title_key_enc, common_key_index, title_id) -> bytes:
|
|||||||
|
|
||||||
|
|
||||||
def decrypt_content(content_enc, title_key, content_index, content_length) -> bytes:
|
def decrypt_content(content_enc, title_key, content_index, content_length) -> bytes:
|
||||||
"""Gets the decrypted version of the encrypted content.
|
"""
|
||||||
|
Gets the decrypted version of the encrypted content.
|
||||||
|
|
||||||
This requires the index of the content to decrypt as it is used as the IV, as well as the content length to adjust
|
This requires the index of the content to decrypt as it is used as the IV, as well as the content length to adjust
|
||||||
padding as necessary.
|
padding as necessary.
|
||||||
@ -76,7 +78,8 @@ def decrypt_content(content_enc, title_key, content_index, content_length) -> by
|
|||||||
|
|
||||||
|
|
||||||
def encrypt_content(content_dec, title_key, content_index) -> bytes:
|
def encrypt_content(content_dec, title_key, content_index) -> bytes:
|
||||||
"""Gets the encrypted version of the decrypted content.
|
"""
|
||||||
|
Gets the encrypted version of the decrypted content.
|
||||||
|
|
||||||
This requires the index of the content to encrypt as it is used as the IV, as well as the content length to adjust
|
This requires the index of the content to encrypt as it is used as the IV, as well as the content length to adjust
|
||||||
padding as necessary.
|
padding as necessary.
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
# "shared.py" from libWiiPy by NinjaCheetah & Contributors
|
# "shared.py" from libWiiPy by NinjaCheetah & Contributors
|
||||||
# https://github.com/NinjaCheetah/libWiiPy
|
# https://github.com/NinjaCheetah/libWiiPy
|
||||||
|
#
|
||||||
|
# This file defines general functions that may be useful in other modules of libWiiPy. Putting them here cuts down on
|
||||||
|
# clutter in other files.
|
||||||
|
|
||||||
def align_value(value, alignment=64):
|
def align_value(value, alignment=64) -> int:
|
||||||
"""Aligns the provided value to the set alignment (defaults to 64).
|
"""
|
||||||
|
Aligns the provided value to the set alignment (defaults to 64).
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
@ -22,8 +26,9 @@ def align_value(value, alignment=64):
|
|||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
def pad_bytes_stream(data, alignment=64):
|
def pad_bytes_stream(data, alignment=64) -> bytes:
|
||||||
"""Pads the provided bytes stream to the provided alignment (defaults to 64).
|
"""
|
||||||
|
Pads the provided bytes stream to the provided alignment (defaults to 64).
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
|
@ -12,8 +12,7 @@ from typing import List
|
|||||||
|
|
||||||
class Ticket:
|
class Ticket:
|
||||||
"""
|
"""
|
||||||
Creates a Ticket object that allows for either loading and editing an existing Ticket or creating one manually if
|
A Ticket object that allows for either loading and editing an existing Ticket or creating one manually if desired.
|
||||||
desired.
|
|
||||||
|
|
||||||
Attributes
|
Attributes
|
||||||
----------
|
----------
|
||||||
@ -58,7 +57,8 @@ class Ticket:
|
|||||||
# TODO: Write in v1 ticket attributes here. This code can currently only handle v0 tickets, and will reject v1.
|
# TODO: Write in v1 ticket attributes here. This code can currently only handle v0 tickets, and will reject v1.
|
||||||
|
|
||||||
def load(self, ticket: bytes) -> None:
|
def load(self, ticket: bytes) -> None:
|
||||||
"""Loads raw Ticket data and sets all attributes of the WAD object. This allows for manipulating an already
|
"""
|
||||||
|
Loads raw Ticket data and sets all attributes of the WAD object. This allows for manipulating an already
|
||||||
existing Ticket.
|
existing Ticket.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
@ -138,7 +138,8 @@ class Ticket:
|
|||||||
self.title_limits_list.append(TitleLimit(limit_type, limit_value))
|
self.title_limits_list.append(TitleLimit(limit_type, limit_value))
|
||||||
|
|
||||||
def dump(self) -> bytes:
|
def dump(self) -> bytes:
|
||||||
"""Dumps the Ticket object back into bytes. This also sets the raw Ticket attribute of Ticket object to the
|
"""
|
||||||
|
Dumps the Ticket object back into bytes. This also sets the raw Ticket attribute of Ticket object to the
|
||||||
dumped data, and triggers load() again to ensure that the raw data and object match.
|
dumped data, and triggers load() again to ensure that the raw data and object match.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
@ -209,8 +210,9 @@ class Ticket:
|
|||||||
# Return the raw TMD for the data contained in the object.
|
# Return the raw TMD for the data contained in the object.
|
||||||
return ticket_data_raw
|
return ticket_data_raw
|
||||||
|
|
||||||
def get_title_id(self):
|
def get_title_id(self) -> str:
|
||||||
"""Gets the Title ID of the ticket's associated title.
|
"""
|
||||||
|
Gets the Title ID of the ticket's associated title.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
@ -220,8 +222,9 @@ class Ticket:
|
|||||||
title_id_str = str(self.title_id.decode())
|
title_id_str = str(self.title_id.decode())
|
||||||
return title_id_str
|
return title_id_str
|
||||||
|
|
||||||
def get_common_key_type(self):
|
def get_common_key_type(self) -> str:
|
||||||
"""Gets the name of the common key used to encrypt the Title Key contained in the ticket.
|
"""
|
||||||
|
Gets the name of the common key used to encrypt the Title Key contained in the ticket.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
@ -240,8 +243,9 @@ class Ticket:
|
|||||||
case 2:
|
case 2:
|
||||||
return "vWii"
|
return "vWii"
|
||||||
|
|
||||||
def get_title_key(self):
|
def get_title_key(self) -> bytes:
|
||||||
"""Gets the decrypted title key contained in the ticket.
|
"""
|
||||||
|
Gets the decrypted title key contained in the ticket.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
@ -251,8 +255,9 @@ class Ticket:
|
|||||||
title_key = decrypt_title_key(self.title_key_enc, self.common_key_index, self.title_id)
|
title_key = decrypt_title_key(self.title_key_enc, self.common_key_index, self.title_id)
|
||||||
return title_key
|
return title_key
|
||||||
|
|
||||||
def set_title_id(self, title_id):
|
def set_title_id(self, title_id) -> None:
|
||||||
"""Sets the Title ID of the title in the Ticket.
|
"""
|
||||||
|
Sets the Title ID of the title in the Ticket.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
|
@ -10,10 +10,15 @@ from .wad import WAD
|
|||||||
|
|
||||||
|
|
||||||
class Title:
|
class Title:
|
||||||
"""Creates a Title object that contains all components of a title, and allows altering them.
|
"""
|
||||||
|
A Title object that contains all components of a title, and allows altering them. Provides higher-level access
|
||||||
|
than manually creating WAD, TMD, Ticket, and ContentRegion objects and ensures that any data that needs to match
|
||||||
|
between files matches.
|
||||||
|
|
||||||
Attributes
|
Attributes
|
||||||
----------
|
----------
|
||||||
|
wad : WAD
|
||||||
|
A WAD object of a WAD containing the title's data.
|
||||||
tmd : TMD
|
tmd : TMD
|
||||||
A TMD object of the title's TMD.
|
A TMD object of the title's TMD.
|
||||||
ticket : Ticket
|
ticket : Ticket
|
||||||
@ -28,7 +33,8 @@ class Title:
|
|||||||
self.content: ContentRegion = ContentRegion()
|
self.content: ContentRegion = ContentRegion()
|
||||||
|
|
||||||
def load_wad(self, wad: bytes) -> None:
|
def load_wad(self, wad: bytes) -> None:
|
||||||
"""Load existing WAD data into the title and create WAD, TMD, Ticket, and ContentRegion objects based off of it
|
"""
|
||||||
|
Load existing WAD data into the title and create WAD, TMD, Ticket, and ContentRegion objects based off of it
|
||||||
to allow you to modify that data. Note that this will overwrite any existing data for this title.
|
to allow you to modify that data. Note that this will overwrite any existing data for this title.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
@ -55,7 +61,8 @@ class Title:
|
|||||||
"invalid.")
|
"invalid.")
|
||||||
|
|
||||||
def dump_wad(self) -> bytes:
|
def dump_wad(self) -> bytes:
|
||||||
"""Dumps all title components (TMD, Ticket, and contents) back into the WAD object, and then dumps the WAD back
|
"""
|
||||||
|
Dumps all title components (TMD, Ticket, and contents) back into the WAD object, and then dumps the WAD back
|
||||||
into raw data and returns it.
|
into raw data and returns it.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
@ -74,7 +81,8 @@ class Title:
|
|||||||
return wad_data
|
return wad_data
|
||||||
|
|
||||||
def load_tmd(self, tmd: bytes) -> None:
|
def load_tmd(self, tmd: bytes) -> None:
|
||||||
"""Load existing TMD data into the title. Note that this will overwrite any existing TMD data for this title.
|
"""
|
||||||
|
Load existing TMD data into the title. Note that this will overwrite any existing TMD data for this title.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
@ -85,7 +93,8 @@ class Title:
|
|||||||
self.tmd.load(tmd)
|
self.tmd.load(tmd)
|
||||||
|
|
||||||
def load_ticket(self, ticket: bytes) -> None:
|
def load_ticket(self, ticket: bytes) -> None:
|
||||||
"""Load existing Ticket data into the title. Note that this will overwrite any existing Ticket data for this
|
"""
|
||||||
|
Load existing Ticket data into the title. Note that this will overwrite any existing Ticket data for this
|
||||||
title.
|
title.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
@ -97,7 +106,8 @@ class Title:
|
|||||||
self.ticket.load(ticket)
|
self.ticket.load(ticket)
|
||||||
|
|
||||||
def load_content_records(self) -> None:
|
def load_content_records(self) -> None:
|
||||||
"""Load content records from the TMD into the ContentRegion to allow loading content files based on the records.
|
"""
|
||||||
|
Load content records from the TMD into the ContentRegion to allow loading content files based on the records.
|
||||||
This requires that a TMD has already been loaded and will throw an exception if it isn't.
|
This requires that a TMD has already been loaded and will throw an exception if it isn't.
|
||||||
"""
|
"""
|
||||||
if not self.tmd.content_records:
|
if not self.tmd.content_records:
|
||||||
@ -106,7 +116,8 @@ class Title:
|
|||||||
self.content.content_records = self.tmd.content_records
|
self.content.content_records = self.tmd.content_records
|
||||||
|
|
||||||
def set_title_id(self, title_id: str) -> None:
|
def set_title_id(self, title_id: str) -> None:
|
||||||
"""Sets the Title ID of the title in both the TMD and Ticket.
|
"""
|
||||||
|
Sets the Title ID of the title in both the TMD and Ticket.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
@ -119,7 +130,8 @@ class Title:
|
|||||||
self.ticket.set_title_id(title_id)
|
self.ticket.set_title_id(title_id)
|
||||||
|
|
||||||
def get_content_by_index(self, index: id) -> bytes:
|
def get_content_by_index(self, index: id) -> bytes:
|
||||||
"""Gets an individual content from the content region based on the provided index, in decrypted form.
|
"""
|
||||||
|
Gets an individual content from the content region based on the provided index, in decrypted form.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
@ -138,7 +150,8 @@ class Title:
|
|||||||
return dec_content
|
return dec_content
|
||||||
|
|
||||||
def get_content_by_cid(self, cid: int) -> bytes:
|
def get_content_by_cid(self, cid: int) -> bytes:
|
||||||
"""Gets an individual content from the content region based on the provided Content ID, in decrypted form.
|
"""
|
||||||
|
Gets an individual content from the content region based on the provided Content ID, in decrypted form.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
@ -158,7 +171,8 @@ class Title:
|
|||||||
|
|
||||||
def set_enc_content(self, enc_content: bytes, cid: int, index: int, content_type: int, content_size: int,
|
def set_enc_content(self, enc_content: bytes, cid: int, index: int, content_type: int, content_size: int,
|
||||||
content_hash: bytes) -> None:
|
content_hash: bytes) -> None:
|
||||||
"""Sets the provided index to a new content with the provided Content ID. Hashes and size of the content are
|
"""
|
||||||
|
Sets the provided index to a new content with the provided Content ID. Hashes and size of the content are
|
||||||
set in the content record, with a new record being added if necessary. The TMD is also updated to match the new
|
set in the content record, with a new record being added if necessary. The TMD is also updated to match the new
|
||||||
records.
|
records.
|
||||||
|
|
||||||
@ -183,7 +197,8 @@ class Title:
|
|||||||
self.tmd.content_records = self.content.content_records
|
self.tmd.content_records = self.content.content_records
|
||||||
|
|
||||||
def set_content(self, dec_content: bytes, cid: int, index: int, content_type: int) -> None:
|
def set_content(self, dec_content: bytes, cid: int, index: int, content_type: int) -> None:
|
||||||
"""Sets the provided index to a new content with the provided Content ID. Hashes and size of the content are
|
"""
|
||||||
|
Sets the provided index to a new content with the provided Content ID. Hashes and size of the content are
|
||||||
set in the content record, with a new record being added if necessary. The Title Key is sourced from this
|
set in the content record, with a new record being added if necessary. The Title Key is sourced from this
|
||||||
title's loaded ticket. The TMD is also updated to match the new records.
|
title's loaded ticket. The TMD is also updated to match the new records.
|
||||||
|
|
||||||
@ -204,7 +219,8 @@ class Title:
|
|||||||
self.tmd.content_records = self.content.content_records
|
self.tmd.content_records = self.content.content_records
|
||||||
|
|
||||||
def load_content(self, dec_content: bytes, index: int) -> None:
|
def load_content(self, dec_content: bytes, index: int) -> None:
|
||||||
"""Loads the provided decrypted content into the content region at the specified index, but first checks to make
|
"""
|
||||||
|
Loads the provided decrypted content into the content region at the specified index, but first checks to make
|
||||||
sure it matches the record at that index before loading. This content will be encrypted when loaded.
|
sure it matches the record at that index before loading. This content will be encrypted when loaded.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
|
@ -12,7 +12,7 @@ from .types import ContentRecord
|
|||||||
|
|
||||||
class TMD:
|
class TMD:
|
||||||
"""
|
"""
|
||||||
Creates a TMD object that allows for either loading and editing an existing TMD or creating one manually if desired.
|
A TMD object that allows for either loading and editing an existing TMD or creating one manually if desired.
|
||||||
|
|
||||||
Attributes
|
Attributes
|
||||||
----------
|
----------
|
||||||
@ -53,7 +53,8 @@ class TMD:
|
|||||||
self.content_records: List[ContentRecord] = []
|
self.content_records: List[ContentRecord] = []
|
||||||
|
|
||||||
def load(self, tmd: bytes) -> None:
|
def load(self, tmd: bytes) -> None:
|
||||||
"""Loads raw TMD data and sets all attributes of the WAD object. This allows for manipulating an already
|
"""
|
||||||
|
Loads raw TMD data and sets all attributes of the WAD object. This allows for manipulating an already
|
||||||
existing TMD.
|
existing TMD.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
@ -138,7 +139,8 @@ class TMD:
|
|||||||
binascii.hexlify(content_record_hdr[4])))
|
binascii.hexlify(content_record_hdr[4])))
|
||||||
|
|
||||||
def dump(self) -> bytes:
|
def dump(self) -> bytes:
|
||||||
"""Dumps the TMD object back into bytes. This also sets the raw TMD attribute of TMD object to the dumped data,
|
"""
|
||||||
|
Dumps the TMD object back into bytes. This also sets the raw TMD attribute of TMD object to the dumped data,
|
||||||
and triggers load() again to ensure that the raw data and object match.
|
and triggers load() again to ensure that the raw data and object match.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
@ -212,8 +214,9 @@ class TMD:
|
|||||||
# Return the raw TMD for the data contained in the object.
|
# Return the raw TMD for the data contained in the object.
|
||||||
return tmd_data_raw
|
return tmd_data_raw
|
||||||
|
|
||||||
def get_title_region(self):
|
def get_title_region(self) -> str:
|
||||||
"""Gets the region of the TMD's associated title.
|
"""
|
||||||
|
Gets the region of the TMD's associated title.
|
||||||
|
|
||||||
Can be one of several possible values:
|
Can be one of several possible values:
|
||||||
'JAP', 'USA', 'EUR', 'NONE', or 'KOR'.
|
'JAP', 'USA', 'EUR', 'NONE', or 'KOR'.
|
||||||
@ -235,8 +238,9 @@ class TMD:
|
|||||||
case 4:
|
case 4:
|
||||||
return "KOR"
|
return "KOR"
|
||||||
|
|
||||||
def get_is_vwii_title(self):
|
def get_is_vwii_title(self) -> bool:
|
||||||
"""Gets whether the TMD is designed for the vWii or not.
|
"""
|
||||||
|
Gets whether the TMD is designed for the vWii or not.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
@ -248,8 +252,9 @@ class TMD:
|
|||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def get_title_type(self):
|
def get_title_type(self) -> str:
|
||||||
"""Gets the type of the TMD's associated title.
|
"""
|
||||||
|
Gets the type of the TMD's associated title.
|
||||||
|
|
||||||
Can be one of several possible values:
|
Can be one of several possible values:
|
||||||
'System', 'Game', 'Channel', 'SystemChannel', 'GameWithChannel', or 'HiddenChannel'
|
'System', 'Game', 'Channel', 'SystemChannel', 'GameWithChannel', or 'HiddenChannel'
|
||||||
@ -279,7 +284,8 @@ class TMD:
|
|||||||
return "Unknown"
|
return "Unknown"
|
||||||
|
|
||||||
def get_content_type(self):
|
def get_content_type(self):
|
||||||
"""Gets the type of content contained in the TMD's associated title.
|
"""
|
||||||
|
Gets the type of content contained in the TMD's associated title.
|
||||||
|
|
||||||
Can be one of several possible values:
|
Can be one of several possible values:
|
||||||
'Normal', 'Development/Unknown', 'Hash Tree', 'DLC', or 'Shared'
|
'Normal', 'Development/Unknown', 'Hash Tree', 'DLC', or 'Shared'
|
||||||
@ -303,8 +309,9 @@ class TMD:
|
|||||||
case _:
|
case _:
|
||||||
return "Unknown"
|
return "Unknown"
|
||||||
|
|
||||||
def get_content_record(self, record):
|
def get_content_record(self, record) -> ContentRecord:
|
||||||
"""Gets the content record at the specified index.
|
"""
|
||||||
|
Gets the content record at the specified index.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
@ -322,8 +329,9 @@ class TMD:
|
|||||||
raise IndexError("Invalid content record! TMD lists '" + str(self.num_contents - 1) +
|
raise IndexError("Invalid content record! TMD lists '" + str(self.num_contents - 1) +
|
||||||
"' contents but index was '" + str(record) + "'!")
|
"' contents but index was '" + str(record) + "'!")
|
||||||
|
|
||||||
def set_title_id(self, title_id):
|
def set_title_id(self, title_id) -> None:
|
||||||
"""Sets the Title ID of the title in the ticket.
|
"""
|
||||||
|
Sets the Title ID of the title in the ticket.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
|
@ -7,7 +7,9 @@ from dataclasses import dataclass
|
|||||||
@dataclass
|
@dataclass
|
||||||
class ContentRecord:
|
class ContentRecord:
|
||||||
"""
|
"""
|
||||||
Creates a content record object that contains the details of a content contained in a title.
|
A content record object that contains the details of a content contained in a title. This information must match
|
||||||
|
the content stored at the index in the record, or else the content will not decrypt properly, as the hash of the
|
||||||
|
decrypted data will not match the hash in the content record.
|
||||||
|
|
||||||
Attributes
|
Attributes
|
||||||
----------
|
----------
|
||||||
@ -31,7 +33,10 @@ class ContentRecord:
|
|||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class TitleLimit:
|
class TitleLimit:
|
||||||
"""Creates a TitleLimit object that contains the type of restriction and the limit.
|
"""
|
||||||
|
A TitleLimit object that contains the type of restriction and the limit. The limit type can be one of the following:
|
||||||
|
0 = None, 1 = Time Limit, 3 = None, or 4 = Launch Count. The maximum usage is then either the time in minutes the
|
||||||
|
title can be played or the maximum number of launches allowed for that title, based on the type of limit applied.
|
||||||
|
|
||||||
Attributes
|
Attributes
|
||||||
----------
|
----------
|
||||||
@ -40,9 +45,8 @@ class TitleLimit:
|
|||||||
maximum_usage : int
|
maximum_usage : int
|
||||||
The maximum value for the type of play limit applied.
|
The maximum value for the type of play limit applied.
|
||||||
"""
|
"""
|
||||||
# The type of play limit applied. The following types exist:
|
# The type of play limit applied.
|
||||||
# 0 = None, 1 = Time Limit, 3 = None, 4 = Launch Count
|
# 0 = None, 1 = Time Limit, 3 = None, 4 = Launch Count
|
||||||
limit_type: int
|
limit_type: int
|
||||||
# The maximum value of the limit applied.
|
# The maximum value of the limit applied.
|
||||||
# This is either the number of minutes for a time limit, or the number of launches for a launch limit.
|
|
||||||
maximum_usage: int
|
maximum_usage: int
|
||||||
|
@ -10,7 +10,24 @@ from .shared import align_value, pad_bytes_stream
|
|||||||
|
|
||||||
class WAD:
|
class WAD:
|
||||||
"""
|
"""
|
||||||
Creates a WAD object that allows for either loading and editing an existing WAD or creating a new WAD from raw data.
|
A WAD object that allows for either loading and editing an existing WAD or creating a new WAD from raw data.
|
||||||
|
|
||||||
|
Attributes
|
||||||
|
----------
|
||||||
|
wad_type : str
|
||||||
|
The type of WAD, either ib for boot2 or Is for normal installable WADs. libWiiPy only supports Is currently.
|
||||||
|
wad_cert_size : int
|
||||||
|
The size of the WAD's certificate.
|
||||||
|
wad_crl_size : int
|
||||||
|
The size of the WAD's crl.
|
||||||
|
wad_tik_size : int
|
||||||
|
The size of the WAD's Ticket.
|
||||||
|
wad_tmd_size : int
|
||||||
|
The size of the WAD's TMD.
|
||||||
|
wad_content_size : int
|
||||||
|
The size of WAD's total content region.
|
||||||
|
wad_meta_size : int
|
||||||
|
The size of the WAD's meta/footer.
|
||||||
"""
|
"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.wad_hdr_size: int = 64
|
self.wad_hdr_size: int = 64
|
||||||
@ -33,7 +50,8 @@ class WAD:
|
|||||||
self.wad_meta_data: bytes = b''
|
self.wad_meta_data: bytes = b''
|
||||||
|
|
||||||
def load(self, wad_data) -> None:
|
def load(self, wad_data) -> None:
|
||||||
"""Loads raw WAD data and sets all attributes of the WAD object. This allows for manipulating an already
|
"""
|
||||||
|
Loads raw WAD data and sets all attributes of the WAD object. This allows for manipulating an already
|
||||||
existing WAD file.
|
existing WAD file.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
@ -114,7 +132,8 @@ class WAD:
|
|||||||
self.wad_meta_data = wad_data.read(self.wad_meta_size)
|
self.wad_meta_data = wad_data.read(self.wad_meta_size)
|
||||||
|
|
||||||
def dump(self) -> bytes:
|
def dump(self) -> bytes:
|
||||||
"""Dumps the WAD object into the raw WAD file. This allows for creating a WAD file from the data contained in
|
"""
|
||||||
|
Dumps the WAD object into the raw WAD file. This allows for creating a WAD file from the data contained in
|
||||||
the WAD object.
|
the WAD object.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
@ -167,8 +186,9 @@ class WAD:
|
|||||||
# Return the raw WAD file for the data contained in the object.
|
# Return the raw WAD file for the data contained in the object.
|
||||||
return wad_data_raw
|
return wad_data_raw
|
||||||
|
|
||||||
def get_wad_type(self):
|
def get_wad_type(self) -> str:
|
||||||
"""Gets the type of the WAD.
|
"""
|
||||||
|
Gets the type of the WAD.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
@ -178,7 +198,8 @@ class WAD:
|
|||||||
return self.wad_type
|
return self.wad_type
|
||||||
|
|
||||||
def get_cert_data(self) -> bytes:
|
def get_cert_data(self) -> bytes:
|
||||||
"""Gets the certificate data from the WAD.
|
"""
|
||||||
|
Gets the certificate data from the WAD.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
@ -188,7 +209,8 @@ class WAD:
|
|||||||
return self.wad_cert_data
|
return self.wad_cert_data
|
||||||
|
|
||||||
def get_crl_data(self) -> bytes:
|
def get_crl_data(self) -> bytes:
|
||||||
"""Gets the crl data from the WAD, if it exists.
|
"""
|
||||||
|
Gets the crl data from the WAD, if it exists.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
@ -198,7 +220,8 @@ class WAD:
|
|||||||
return self.wad_crl_data
|
return self.wad_crl_data
|
||||||
|
|
||||||
def get_ticket_data(self) -> bytes:
|
def get_ticket_data(self) -> bytes:
|
||||||
"""Gets the ticket data from the WAD.
|
"""
|
||||||
|
Gets the ticket data from the WAD.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
@ -208,7 +231,8 @@ class WAD:
|
|||||||
return self.wad_tik_data
|
return self.wad_tik_data
|
||||||
|
|
||||||
def get_tmd_data(self) -> bytes:
|
def get_tmd_data(self) -> bytes:
|
||||||
"""Returns the TMD data from the WAD.
|
"""
|
||||||
|
Returns the TMD data from the WAD.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
@ -218,7 +242,8 @@ class WAD:
|
|||||||
return self.wad_tmd_data
|
return self.wad_tmd_data
|
||||||
|
|
||||||
def get_content_data(self) -> bytes:
|
def get_content_data(self) -> bytes:
|
||||||
"""Gets the content of the WAD.
|
"""
|
||||||
|
Gets the content of the WAD.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
@ -228,7 +253,8 @@ class WAD:
|
|||||||
return self.wad_content_data
|
return self.wad_content_data
|
||||||
|
|
||||||
def get_meta_data(self) -> bytes:
|
def get_meta_data(self) -> bytes:
|
||||||
"""Gets the meta region of the WAD, which is typically unused.
|
"""
|
||||||
|
Gets the meta region of the WAD, which is typically unused.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
@ -238,7 +264,8 @@ class WAD:
|
|||||||
return self.wad_meta_data
|
return self.wad_meta_data
|
||||||
|
|
||||||
def set_cert_data(self, cert_data) -> None:
|
def set_cert_data(self, cert_data) -> None:
|
||||||
"""Sets the certificate data of the WAD. Also calculates the new size.
|
"""
|
||||||
|
Sets the certificate data of the WAD. Also calculates the new size.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
@ -250,7 +277,8 @@ class WAD:
|
|||||||
self.wad_cert_size = len(cert_data)
|
self.wad_cert_size = len(cert_data)
|
||||||
|
|
||||||
def set_crl_data(self, crl_data) -> None:
|
def set_crl_data(self, crl_data) -> None:
|
||||||
"""Sets the crl data of the WAD. Also calculates the new size.
|
"""
|
||||||
|
Sets the crl data of the WAD. Also calculates the new size.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
@ -262,7 +290,8 @@ class WAD:
|
|||||||
self.wad_crl_size = len(crl_data)
|
self.wad_crl_size = len(crl_data)
|
||||||
|
|
||||||
def set_tmd_data(self, tmd_data) -> None:
|
def set_tmd_data(self, tmd_data) -> None:
|
||||||
"""Sets the TMD data of the WAD. Also calculates the new size.
|
"""
|
||||||
|
Sets the TMD data of the WAD. Also calculates the new size.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
@ -274,7 +303,8 @@ class WAD:
|
|||||||
self.wad_tmd_size = len(tmd_data)
|
self.wad_tmd_size = len(tmd_data)
|
||||||
|
|
||||||
def set_ticket_data(self, tik_data) -> None:
|
def set_ticket_data(self, tik_data) -> None:
|
||||||
"""Sets the Ticket data of the WAD. Also calculates the new size.
|
"""
|
||||||
|
Sets the Ticket data of the WAD. Also calculates the new size.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
@ -286,7 +316,8 @@ class WAD:
|
|||||||
self.wad_tik_size = len(tik_data)
|
self.wad_tik_size = len(tik_data)
|
||||||
|
|
||||||
def set_content_data(self, content_data) -> None:
|
def set_content_data(self, content_data) -> None:
|
||||||
"""Sets the content data of the WAD. Also calculates the new size.
|
"""
|
||||||
|
Sets the content data of the WAD. Also calculates the new size.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
@ -298,7 +329,8 @@ class WAD:
|
|||||||
self.wad_content_size = len(content_data)
|
self.wad_content_size = len(content_data)
|
||||||
|
|
||||||
def set_meta_data(self, meta_data) -> None:
|
def set_meta_data(self, meta_data) -> None:
|
||||||
"""Sets the meta data of the WAD. Also calculates the new size.
|
"""
|
||||||
|
Sets the meta data of the WAD. Also calculates the new size.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
|
Loading…
x
Reference in New Issue
Block a user