|
4 | 4 | ''' |
5 | 5 |
|
6 | 6 | # NiemaFS imports |
7 | | -from niemafs.common import clean_string, FileSystem |
| 7 | +from niemafs.common import clean_string, FileSystem, safename |
8 | 8 | from niemafs.gcm import GcmFS |
9 | 9 |
|
10 | 10 | # imports |
| 11 | +from Crypto.Cipher import AES |
11 | 12 | from datetime import datetime |
| 13 | +from multiprocessing import Pool |
12 | 14 | from pathlib import Path |
13 | 15 | from struct import unpack |
14 | 16 | from warnings import warn |
|
30 | 32 | 4: 'Korea', |
31 | 33 | } |
32 | 34 |
|
| 35 | +# helper function for multiprocessing of AES decryption |
| 36 | +def aes_helper(aes_tup): |
| 37 | + decrypt_key, cluster_data_encrypted = aes_tup |
| 38 | + aes = AES.new(decrypt_key, AES.MODE_CBC, cluster_data_encrypted[0x3D0 : 0x3E0]) |
| 39 | + return aes.decrypt(cluster_data_encrypted[0x0400:]) |
| 40 | + |
33 | 41 | class WiiFS(FileSystem): |
34 | 42 | '''Class to represent a `Nintendo Wii DVD <https://wiibrew.org/wiki/Wii_disc#%22System_Area%22>`_.''' |
35 | 43 | def __init__(self, file_obj, path=None): |
@@ -272,9 +280,6 @@ def parse_ticket(data): |
272 | 280 | return out |
273 | 281 |
|
274 | 282 | def __iter__(self): |
275 | | - # import PyCryptodome within WiiFS to allow people to use the other NiemaFS classes without it |
276 | | - from Crypto.Cipher import AES |
277 | | - |
278 | 283 | # parse each partition table |
279 | 284 | for volume_num, parsed_partition_table in enumerate(self.parse_partition_tables()): |
280 | 285 | volume_path = Path('Volume %d' % volume_num) |
@@ -317,19 +322,16 @@ def __iter__(self): |
317 | 322 | data_start_offset = partition['offset'] + partition_data_offset |
318 | 323 | data_end_offset = data_start_offset + partition_data_size |
319 | 324 | if WiiFS.parse_header(self.get_header())['disable_disc_encryption'] == 0: |
320 | | - data_decrypted = b'' |
321 | | - for cluster_offset in range(data_start_offset, data_end_offset, 0x8000): |
322 | | - cluster_data_encrypted = self.read_file(cluster_offset, 0x8000) |
323 | | - aes = AES.new(decrypt_key, AES.MODE_CBC, cluster_data_encrypted[0x3D0 : 0x3E0]) |
324 | | - data_decrypted += aes.decrypt(cluster_data_encrypted[0x0400:]) |
| 325 | + with Pool(processes=None) as pool: |
| 326 | + data_decrypted = b''.join(pool.map(aes_helper, [(decrypt_key, self.read_file(cluster_offset, 0x8000)) for cluster_offset in range(data_start_offset, data_end_offset, 0x8000)])) |
325 | 327 | else: |
326 | 328 | data_decrypted = self.read_file(data_start_offset, partition_data_size) |
327 | 329 |
|
328 | 330 | # yield partition header data |
329 | 331 | partition_header = WiiFS.parse_header(data_decrypted[0x0000 : 0x0420]) |
330 | | - partition_path = volume_path / ('Partition %d (%s) (%s%s) (%s)' % (partition_num, partition_type.capitalize(), partition_header['game_code'], partition_header['maker_code'], partition_header['game_name'])) |
| 332 | + partition_path = volume_path / ('Partition %d (%s) (%s%s) (%s)' % (partition_num, partition_type.capitalize(), partition_header['game_code'], partition_header['maker_code'], safename(partition_header['game_name']))) |
331 | 333 | yield (partition_path, None, None) |
332 | | - partition_header_path = partition_path / '__PARTITION_HEADER_NIEMAFS' |
| 334 | + partition_header_path = partition_path / '___PARTITION_HEADER_NIEMAFS' |
333 | 335 | yield (partition_header_path, None, None) |
334 | 336 | yield (partition_header_path / 'ticket.bin', None, ticket) |
335 | 337 | yield (partition_header_path / 'tmd.bin', None, tmd) |
|
0 commit comments