mirror of
https://github.com/xprism1/ntool.git
synced 2025-06-18 15:55:31 -04:00
94 lines
2.9 KiB
Python
94 lines
2.9 KiB
Python
from .common import *
|
|
from .keys import *
|
|
from .ctr_cia import CIAReader
|
|
|
|
class cntRecord(Structure):
|
|
_pack_ = 1
|
|
|
|
_fields_ = [
|
|
('offset', c_uint32),
|
|
('offset_end', c_uint32),
|
|
]
|
|
|
|
def __new__(cls, buf):
|
|
return cls.from_buffer_copy(buf)
|
|
|
|
def __init__(self, data):
|
|
pass
|
|
|
|
class cntHdr(Structure):
|
|
_pack_ = 1
|
|
|
|
_fields_ = [
|
|
('magic', c_char * 4),
|
|
('unk', c_uint8 * 0xBFC),
|
|
('content_records', cntRecord * 0x100)
|
|
]
|
|
|
|
def __new__(cls, buf):
|
|
return cls.from_buffer_copy(buf)
|
|
|
|
def __init__(self, data):
|
|
pass
|
|
|
|
class cntReader:
|
|
def __init__(self, cnt, cuplist=''): # files named 'Contents.cnt' and 'CupList' respectively
|
|
self.cnt = cnt
|
|
self.cuplist = cuplist
|
|
files = {}
|
|
|
|
if self.cuplist != '':
|
|
with open(cuplist, 'rb') as f:
|
|
cupdata = f.read()
|
|
|
|
tidlist = []
|
|
for i in range(0, 0x800, 8):
|
|
if cupdata[i:i + 8] == b'\x00' * 8:
|
|
break
|
|
tidlist.append(hex(readle(cupdata[i:i + 8]))[2:].zfill(16))
|
|
self.tidlist = tidlist
|
|
|
|
with open(cnt, 'rb') as f:
|
|
self.cnt_hdr = cntHdr(f.read(0x1400))
|
|
|
|
for i in range(len(tidlist)):
|
|
files[f'{tidlist[i]}.cia'] = {
|
|
'size': self.cnt_hdr.content_records[i].offset_end - self.cnt_hdr.content_records[i].offset,
|
|
'offset': self.cnt_hdr.content_records[i].offset + 0xC00 # Offsets are relative from the start of the content records
|
|
}
|
|
else:
|
|
with open(cnt, 'rb') as f:
|
|
f.seek(0xC00)
|
|
content_records = f.read(0x800)
|
|
for i in range(0, 0x800, 8):
|
|
offset = readle(content_records[i:i + 4])
|
|
offset_end = readle(content_records[i + 4:i + 8])
|
|
if offset == 0:
|
|
break
|
|
files[f'{(i // 8) + 1}.cia'] = {
|
|
'size': offset_end - offset,
|
|
'offset': offset + 0xC00
|
|
}
|
|
self.files = files
|
|
|
|
def extract(self):
|
|
output_dir = 'updates/'
|
|
if not os.path.isdir(output_dir):
|
|
os.mkdir(output_dir)
|
|
|
|
f = open(self.cnt, 'rb')
|
|
for name, info in self.files.items():
|
|
f.seek(info['offset'])
|
|
g = open(os.path.join(output_dir, name), 'wb')
|
|
for data in read_chunks(f, info['size']):
|
|
g.write(data)
|
|
g.close()
|
|
|
|
# Rename CIAs if no cuplist
|
|
if self.cuplist == '':
|
|
cia = CIAReader(os.path.join(output_dir, name))
|
|
titleID = cia.tmd.titleID
|
|
os.rename(os.path.join(output_dir, name), f"{os.path.join(output_dir, titleID)}.cia")
|
|
|
|
f.close()
|
|
print(f'Extracted to {output_dir}') |