mirror of
https://github.com/NinjaCheetah/libWiiPy.git
synced 2025-04-26 13:21:01 -04:00
Entirely restructured package to make it more of a proper Python package
THIS IS A BREAKING COMMIT! ALL v0.2.X BASED PROJECTS WILL NEED TO BE UPDATED TO SUPPORT v0.3.X!
This commit is contained in:
parent
bc9224e40b
commit
ade4b68394
0
src/__init__.py
Normal file
0
src/__init__.py
Normal file
@ -1,14 +1,9 @@
|
||||
# "__init__.py" from libWiiPy by NinjaCheetah & Contributors
|
||||
# https://github.com/NinjaCheetah/libWiiPy
|
||||
#
|
||||
# These are the essential modules from libWiiPy that you'd probably want imported by default.
|
||||
# These are the essential submodules from libWiiPy that you'd probably want imported by default.
|
||||
|
||||
from .commonkeys import *
|
||||
from .content import *
|
||||
from .ticket import *
|
||||
from .crypto import *
|
||||
from .title import *
|
||||
from .tmd import *
|
||||
from .wad import *
|
||||
from .nus import *
|
||||
from .u8 import *
|
||||
__all__ = ["archive", "title"]
|
||||
|
||||
from . import archive
|
||||
from . import title
|
||||
|
4
src/libWiiPy/archive/__init__.py
Normal file
4
src/libWiiPy/archive/__init__.py
Normal file
@ -0,0 +1,4 @@
|
||||
# "archive/__init__.py" from libWiiPy by NinjaCheetah & Contributors
|
||||
# https://github.com/NinjaCheetah/libWiiPy
|
||||
|
||||
from .u8 import *
|
@ -1,4 +1,4 @@
|
||||
# "u8.py" from libWiiPy by NinjaCheetah & Contributors
|
||||
# "archive/u8.py" from libWiiPy by NinjaCheetah & Contributors
|
||||
# https://github.com/NinjaCheetah/libWiiPy
|
||||
#
|
||||
# See https://wiibrew.org/wiki/U8_archive for details about the U8 archive format
|
||||
@ -6,14 +6,38 @@
|
||||
import io
|
||||
import binascii
|
||||
import os
|
||||
from dataclasses import dataclass
|
||||
from typing import List
|
||||
from .types import U8Node
|
||||
|
||||
|
||||
@dataclass
|
||||
class U8Node:
|
||||
"""
|
||||
A U8Node object that contains the data of a single node in a U8 file header. Each node keeps track of whether this
|
||||
node is for a file or directory, the offset of the name of the file/directory, the offset of the data for the file/
|
||||
directory, and the size of the data.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
type : int
|
||||
Whether this node refers to a file or a directory. Either 0x0000 for files, or 0x0100 for directories.
|
||||
name_offset : int
|
||||
The offset of the name of the file/directory this node refers to.
|
||||
data_offset : int
|
||||
The offset of the data for the file/directory this node refers to.
|
||||
size : int
|
||||
The size of the data for this node.
|
||||
"""
|
||||
type: int
|
||||
name_offset: int
|
||||
data_offset: int
|
||||
size: int
|
||||
|
||||
|
||||
class U8Archive:
|
||||
def __init__(self):
|
||||
"""
|
||||
A U8 object that allows for extracting and packing U8 archives.
|
||||
A U8 object that allows for managing the contents of a U8 archive.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
@ -77,33 +101,54 @@ class U8Archive:
|
||||
else:
|
||||
self.u8_file_data_list.append(b'')
|
||||
|
||||
def extract_to_folder(self, output_folder) -> None:
|
||||
if os.path.isdir(output_folder):
|
||||
raise ValueError("Output folder already exists!")
|
||||
if self.u8_node_list is []:
|
||||
raise ValueError("No U8 file is loaded!")
|
||||
def dump(self) -> None:
|
||||
"""
|
||||
Dumps the U8Archive object into a U8 file.
|
||||
"""
|
||||
u8_data = b''
|
||||
# Magic number.
|
||||
u8_data += b'\x55\xAA\x38\x2D'
|
||||
# Root node offset (this is always 0x20).
|
||||
u8_data += int.to_bytes(0x20, 4)
|
||||
|
||||
os.mkdir(output_folder)
|
||||
|
||||
current_dir = ""
|
||||
for node in range(len(self.u8_node_list)):
|
||||
if self.u8_node_list[node].name_offset != 0:
|
||||
if self.u8_node_list[node].type == 256:
|
||||
if self.u8_node_list[node].data_offset == 0:
|
||||
os.mkdir(os.path.join(output_folder, self.file_name_list[node]))
|
||||
current_dir = self.file_name_list[node]
|
||||
elif self.u8_node_list[node].data_offset < node:
|
||||
lower_path = os.path.join(output_folder, current_dir)
|
||||
os.mkdir(os.path.join(lower_path, self.file_name_list[node]))
|
||||
current_dir = os.path.join(current_dir, self.file_name_list[node])
|
||||
elif self.u8_node_list[node].type == 0:
|
||||
def extract_u8(u8_data, output_folder) -> None:
|
||||
if os.path.isdir(output_folder):
|
||||
raise ValueError("Output folder already exists!")
|
||||
|
||||
os.mkdir(output_folder)
|
||||
|
||||
u8_archive = U8Archive()
|
||||
u8_archive.load(u8_data)
|
||||
|
||||
current_dir = ""
|
||||
for node in range(len(u8_archive.u8_node_list)):
|
||||
if u8_archive.u8_node_list[node].name_offset != 0:
|
||||
if u8_archive.u8_node_list[node].type == 256:
|
||||
if u8_archive.u8_node_list[node].data_offset == 0:
|
||||
os.mkdir(os.path.join(output_folder, u8_archive.file_name_list[node]))
|
||||
current_dir = u8_archive.file_name_list[node]
|
||||
elif u8_archive.u8_node_list[node].data_offset < node:
|
||||
lower_path = os.path.join(output_folder, current_dir)
|
||||
output_file = open(os.path.join(lower_path, self.file_name_list[node]), "wb")
|
||||
output_file.write(self.u8_file_data_list[node])
|
||||
output_file.close()
|
||||
|
||||
def pack_from_folder(self, input_folder) -> None:
|
||||
if not os.path.isdir(input_folder):
|
||||
raise ValueError("Input folder does not exist!")
|
||||
os.mkdir(os.path.join(lower_path, u8_archive.file_name_list[node]))
|
||||
current_dir = os.path.join(current_dir, u8_archive.file_name_list[node])
|
||||
elif u8_archive.u8_node_list[node].type == 0:
|
||||
lower_path = os.path.join(output_folder, current_dir)
|
||||
output_file = open(os.path.join(lower_path, u8_archive.file_name_list[node]), "wb")
|
||||
output_file.write(u8_archive.u8_file_data_list[node])
|
||||
output_file.close()
|
||||
|
||||
|
||||
def pack_u8(input_data) -> None:
|
||||
if os.path.isdir(input_data):
|
||||
raise ValueError("Only single-file packing is currently supported!")
|
||||
elif os.path.isfile(input_data):
|
||||
with open(input_data, "rb") as f:
|
||||
u8_archive = U8Archive()
|
||||
|
||||
file_name = os.path.basename(input_data)
|
||||
|
||||
u8_archive.file_name_list.append(file_name)
|
||||
u8_archive.u8_file_data_list.append(f.read())
|
||||
|
||||
|
8
src/libWiiPy/title/__init__.py
Normal file
8
src/libWiiPy/title/__init__.py
Normal file
@ -0,0 +1,8 @@
|
||||
# "title/__init__.py" from libWiiPy by NinjaCheetah & Contributors
|
||||
# https://github.com/NinjaCheetah/libWiiPy
|
||||
|
||||
from .content import *
|
||||
from .ticket import *
|
||||
from .title import *
|
||||
from .tmd import *
|
||||
from .wad import *
|
@ -1,4 +1,4 @@
|
||||
# "commonkeys.py" from libWiiPy by NinjaCheetah & Contributors
|
||||
# "title/commonkeys.py" from libWiiPy by NinjaCheetah & Contributors
|
||||
# https://github.com/NinjaCheetah/libWiiPy
|
||||
|
||||
import binascii
|
@ -1,4 +1,4 @@
|
||||
# "content.py" from libWiiPy by NinjaCheetah & Contributors
|
||||
# "title/content.py" from libWiiPy by NinjaCheetah & Contributors
|
||||
# https://github.com/NinjaCheetah/libWiiPy
|
||||
#
|
||||
# See https://wiibrew.org/wiki/Title for details about how titles are formatted
|
||||
@ -7,8 +7,8 @@ import io
|
||||
import sys
|
||||
import hashlib
|
||||
from typing import List
|
||||
from .types import ContentRecord
|
||||
from .crypto import decrypt_content, encrypt_content
|
||||
from src.libWiiPy.types import ContentRecord
|
||||
from src.libWiiPy.title.crypto import decrypt_content, encrypt_content
|
||||
|
||||
|
||||
class ContentRegion:
|
@ -1,9 +1,9 @@
|
||||
# "crypto.py" from libWiiPy by NinjaCheetah & Contributors
|
||||
# "title/crypto.py" from libWiiPy by NinjaCheetah & Contributors
|
||||
# https://github.com/NinjaCheetah/libWiiPy
|
||||
|
||||
import struct
|
||||
from .commonkeys import get_common_key
|
||||
from .shared import convert_tid_to_iv
|
||||
from src.libWiiPy.title.commonkeys import get_common_key
|
||||
from src.libWiiPy.shared import convert_tid_to_iv
|
||||
|
||||
from Crypto.Cipher import AES
|
||||
|
@ -1,4 +1,4 @@
|
||||
# "nus.py" from libWiiPy by NinjaCheetah & Contributors
|
||||
# "title/nus.py" from libWiiPy by NinjaCheetah & Contributors
|
||||
# https://github.com/NinjaCheetah/libWiiPy
|
||||
#
|
||||
# See https://wiibrew.org/wiki/NUS for details about the NUS
|
||||
@ -6,9 +6,9 @@
|
||||
import requests
|
||||
import hashlib
|
||||
from typing import List
|
||||
from .title import Title
|
||||
from .tmd import TMD
|
||||
from .ticket import Ticket
|
||||
from src.libWiiPy.title.title import Title
|
||||
from src.libWiiPy.title.tmd import TMD
|
||||
from src.libWiiPy.title.ticket import Ticket
|
||||
|
||||
nus_endpoint = ["http://nus.cdn.shop.wii.com/ccs/download/", "http://ccs.cdn.wup.shop.nintendo.net/ccs/download/"]
|
||||
|
@ -1,12 +1,12 @@
|
||||
# "ticket.py" from libWiiPy by NinjaCheetah & Contributors
|
||||
# "title/ticket.py" from libWiiPy by NinjaCheetah & Contributors
|
||||
# https://github.com/NinjaCheetah/libWiiPy
|
||||
#
|
||||
# See https://wiibrew.org/wiki/Ticket for details about the ticket format
|
||||
|
||||
import io
|
||||
import binascii
|
||||
from .crypto import decrypt_title_key
|
||||
from .types import TitleLimit
|
||||
from src.libWiiPy.title.crypto import decrypt_title_key
|
||||
from src.libWiiPy.types import TitleLimit
|
||||
from typing import List
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
# "title.py" from libWiiPy by NinjaCheetah & Contributors
|
||||
# "title/title.py" from libWiiPy by NinjaCheetah & Contributors
|
||||
# https://github.com/NinjaCheetah/libWiiPy
|
||||
#
|
||||
# See https://wiibrew.org/wiki/Title for details about how titles are formatted
|
||||
|
||||
from .content import ContentRegion
|
||||
from .ticket import Ticket
|
||||
from .tmd import TMD
|
||||
from .wad import WAD
|
||||
from src.libWiiPy.title.content import ContentRegion
|
||||
from src.libWiiPy.title.ticket import Ticket
|
||||
from src.libWiiPy.title.tmd import TMD
|
||||
from src.libWiiPy.title.wad import WAD
|
||||
|
||||
|
||||
class Title:
|
@ -1,4 +1,4 @@
|
||||
# "tmd.py" from libWiiPy by NinjaCheetah & Contributors
|
||||
# "title/tmd.py" from libWiiPy by NinjaCheetah & Contributors
|
||||
# https://github.com/NinjaCheetah/libWiiPy
|
||||
#
|
||||
# See https://wiibrew.org/wiki/Title_metadata for details about the TMD format
|
||||
@ -7,7 +7,7 @@ import io
|
||||
import binascii
|
||||
import struct
|
||||
from typing import List
|
||||
from .types import ContentRecord
|
||||
from src.libWiiPy.types import ContentRecord
|
||||
|
||||
|
||||
class TMD:
|
@ -1,11 +1,11 @@
|
||||
# "wad.py" from libWiiPy by NinjaCheetah & Contributors
|
||||
# "title/wad.py" from libWiiPy by NinjaCheetah & Contributors
|
||||
# https://github.com/NinjaCheetah/libWiiPy
|
||||
#
|
||||
# See https://wiibrew.org/wiki/WAD_files for details about the WAD format
|
||||
|
||||
import io
|
||||
import binascii
|
||||
from .shared import align_value, pad_bytes
|
||||
from src.libWiiPy.shared import align_value, pad_bytes
|
||||
|
||||
|
||||
class WAD:
|
@ -49,27 +49,3 @@ class TitleLimit:
|
||||
limit_type: int
|
||||
# The maximum value of the limit applied.
|
||||
maximum_usage: int
|
||||
|
||||
|
||||
@dataclass
|
||||
class U8Node:
|
||||
"""
|
||||
A U8Node object that contains the data of a single node in a U8 file header. Each node keeps track of whether this
|
||||
node is for a file or directory, the offset of the name of the file/directory, the offset of the data for the file/
|
||||
directory, and the size of the data.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
type : int
|
||||
Whether this node refers to a file or a directory. Either 0x0000 for files, or 0x0100 for directories.
|
||||
name_offset : int
|
||||
The offset of the name of the file/directory this node refers to.
|
||||
data_offset : int
|
||||
The offset of the data for the file/directory this node refers to.
|
||||
size : int
|
||||
The size of the data for this node.
|
||||
"""
|
||||
type: int
|
||||
name_offset: int
|
||||
data_offset: int
|
||||
size: int
|
||||
|
Loading…
x
Reference in New Issue
Block a user