mirror of
https://github.com/xprism1/ntool.git
synced 2025-06-19 00:45:34 -04:00
ctr_romfs: add support for reading L3 only
This commit is contained in:
parent
2417b6831d
commit
1865b2831c
109
lib/ctr_romfs.py
109
lib/ctr_romfs.py
@ -118,45 +118,49 @@ def calc_path_hash(name, parent_off):
|
|||||||
return h
|
return h
|
||||||
|
|
||||||
class RomFSReader:
|
class RomFSReader:
|
||||||
def __init__(self, file):
|
def __init__(self, file, lvl3only=False):
|
||||||
self.file = file
|
self.file = file
|
||||||
|
self.lvl3only = lvl3only
|
||||||
|
|
||||||
with open(file, 'rb') as f:
|
if not lvl3only:
|
||||||
self.hdr = RomFSHdr(f.read(0x5C))
|
with open(file, 'rb') as f:
|
||||||
|
self.hdr = RomFSHdr(f.read(0x5C))
|
||||||
|
|
||||||
self.lvl1_block_size = 1 << self.hdr.lvl1_block_size
|
self.lvl1_block_size = 1 << self.hdr.lvl1_block_size
|
||||||
self.lvl2_block_size = 1 << self.hdr.lvl2_block_size
|
self.lvl2_block_size = 1 << self.hdr.lvl2_block_size
|
||||||
self.lvl3_block_size = 1 << self.hdr.lvl3_block_size
|
self.lvl3_block_size = 1 << self.hdr.lvl3_block_size
|
||||||
|
|
||||||
# Get offsets for RomFS components
|
# Get offsets for RomFS components
|
||||||
hashes = {}
|
hashes = {}
|
||||||
curr = 0x60
|
curr = 0x60
|
||||||
|
|
||||||
hashes['Master Hash'] = {
|
hashes['Master Hash'] = {
|
||||||
'size': self.hdr.master_hash_size,
|
'size': self.hdr.master_hash_size,
|
||||||
'offset': curr
|
'offset': curr
|
||||||
}
|
}
|
||||||
curr += hashes['Master Hash']['size']
|
curr += hashes['Master Hash']['size']
|
||||||
|
|
||||||
curr += align(curr, self.lvl3_block_size)
|
curr += align(curr, self.lvl3_block_size)
|
||||||
self.lvl3_offset = curr
|
self.lvl3_offset = curr
|
||||||
curr += self.hdr.lvl3_size
|
curr += self.hdr.lvl3_size
|
||||||
|
|
||||||
curr += align(curr, self.lvl1_block_size)
|
curr += align(curr, self.lvl1_block_size)
|
||||||
hashes['Level 1'] = {
|
hashes['Level 1'] = {
|
||||||
'size': self.hdr.lvl1_hash_size,
|
'size': self.hdr.lvl1_hash_size,
|
||||||
'offset': curr
|
'offset': curr
|
||||||
}
|
}
|
||||||
curr += hashes['Level 1']['size']
|
curr += hashes['Level 1']['size']
|
||||||
|
|
||||||
curr += align(curr, self.lvl2_block_size)
|
curr += align(curr, self.lvl2_block_size)
|
||||||
hashes['Level 2'] = {
|
hashes['Level 2'] = {
|
||||||
'size': self.hdr.lvl2_hash_size,
|
'size': self.hdr.lvl2_hash_size,
|
||||||
'offset': curr
|
'offset': curr
|
||||||
}
|
}
|
||||||
curr += hashes['Level 2']['size']
|
curr += hashes['Level 2']['size']
|
||||||
|
|
||||||
self.hashes = hashes
|
self.hashes = hashes
|
||||||
|
else:
|
||||||
|
self.lvl3_offset = 0
|
||||||
|
|
||||||
# Parse level 3 (actual data)
|
# Parse level 3 (actual data)
|
||||||
self.files = {}
|
self.files = {}
|
||||||
@ -216,31 +220,32 @@ class RomFSReader:
|
|||||||
print(f'Extracted to {output_dir}')
|
print(f'Extracted to {output_dir}')
|
||||||
|
|
||||||
def verify(self):
|
def verify(self):
|
||||||
f = open(self.file, 'rb')
|
if not self.lvl3only:
|
||||||
|
f = open(self.file, 'rb')
|
||||||
|
|
||||||
hash_check = []
|
hash_check = []
|
||||||
hash_check_info = [
|
hash_check_info = [
|
||||||
('Master Hash', self.hashes['Level 1']['offset'], self.lvl1_block_size), # Master hash verifies level 1
|
('Master Hash', self.hashes['Level 1']['offset'], self.lvl1_block_size), # Master hash verifies level 1
|
||||||
('Level 1', self.hashes['Level 2']['offset'], self.lvl2_block_size), # Level 1 verifies level 2
|
('Level 1', self.hashes['Level 2']['offset'], self.lvl2_block_size), # Level 1 verifies level 2
|
||||||
('Level 2', self.lvl3_offset, self.lvl3_block_size) # Level 2 verifies level 3
|
('Level 2', self.lvl3_offset, self.lvl3_block_size) # Level 2 verifies level 3
|
||||||
]
|
]
|
||||||
for name, off, block_size in hash_check_info:
|
for name, off, block_size in hash_check_info:
|
||||||
f.seek(self.hashes[name]['offset'])
|
f.seek(self.hashes[name]['offset'])
|
||||||
hashes = f.read(self.hashes[name]['size'])
|
hashes = f.read(self.hashes[name]['size'])
|
||||||
num_blocks = len(hashes) // 0x20
|
num_blocks = len(hashes) // 0x20
|
||||||
checks = []
|
checks = []
|
||||||
f.seek(off)
|
f.seek(off)
|
||||||
|
|
||||||
for i in range(num_blocks):
|
for i in range(num_blocks):
|
||||||
h = hashlib.sha256()
|
h = hashlib.sha256()
|
||||||
h.update(f.read(block_size))
|
h.update(f.read(block_size))
|
||||||
checks.append(h.digest() == hashes[i * 0x20:(i + 1) * 0x20])
|
checks.append(h.digest() == hashes[i * 0x20:(i + 1) * 0x20])
|
||||||
hash_check.append((name, all(checks)))
|
hash_check.append((name, all(checks)))
|
||||||
|
|
||||||
f.close()
|
f.close()
|
||||||
print("Hashes:")
|
print("Hashes:")
|
||||||
for i in hash_check:
|
for i in hash_check:
|
||||||
print(' > {0:15} {1:4}'.format(i[0] + ':', 'GOOD' if i[1] else 'FAIL'))
|
print(' > {0:15} {1:4}'.format(i[0] + ':', 'GOOD' if i[1] else 'FAIL'))
|
||||||
|
|
||||||
class RomFSBuilder:
|
class RomFSBuilder:
|
||||||
def __init__(self, romfs_dir='', out='romfs.bin'):
|
def __init__(self, romfs_dir='', out='romfs.bin'):
|
||||||
|
Loading…
Reference in New Issue
Block a user