mirror of
https://github.com/xprism1/ntool.git
synced 2025-06-18 17:55:33 -04:00
ctr_cnt: add support for cnt without CupList
This commit is contained in:
parent
1865b2831c
commit
5b4291ee33
@ -31,8 +31,8 @@ python3 ntool.py cci_retail2dev <path_to_cci> (--out <path_to_output_file>)
|
|||||||
- **WARNING: Only perform this on SysNAND if you are able to use ntrboot to recover from a brick!**
|
- **WARNING: Only perform this on SysNAND if you are able to use ntrboot to recover from a brick!**
|
||||||
- First, obtain the SystemUpdaterForCTR zip file from NDP if you have a o3DS/o3DS XL/2DS. For n3DS/n3DS XL/n2DS XL, obtain the SystemUpdaterForSNAKE zip file instead
|
- First, obtain the SystemUpdaterForCTR zip file from NDP if you have a o3DS/o3DS XL/2DS. For n3DS/n3DS XL/n2DS XL, obtain the SystemUpdaterForSNAKE zip file instead
|
||||||
- Extract the zip file, and choose the appropriate .csu file for your 3DS's region
|
- Extract the zip file, and choose the appropriate .csu file for your 3DS's region
|
||||||
- Run `python3 ntool.py csu2retailcias <path_to_csu> updates/`
|
- Run `python3 ntool.py csu2retailcias <path_to_csu>`
|
||||||
- Place the `updates` folder in the root of your 3DS's SD
|
- Place the `updates_retail` folder in the root of your 3DS's SD and rename it to `updates`
|
||||||
- Install [sysUpdater](https://github.com/profi200/sysUpdater), launch it and follow the on-screen instructions
|
- Install [sysUpdater](https://github.com/profi200/sysUpdater), launch it and follow the on-screen instructions
|
||||||
- You may need to enable `Set developer UNITINFO` in Luma3DS settings
|
- You may need to enable `Set developer UNITINFO` in Luma3DS settings
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
from .common import *
|
from .common import *
|
||||||
from .keys import *
|
from .keys import *
|
||||||
|
from .ctr_cia import CIAReader
|
||||||
|
|
||||||
class cntRecord(Structure):
|
class cntRecord(Structure):
|
||||||
_pack_ = 1
|
_pack_ = 1
|
||||||
@ -31,29 +32,43 @@ class cntHdr(Structure):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
class cntReader:
|
class cntReader:
|
||||||
def __init__(self, cuplist, cnt): # files named 'CupList' and 'Contents.cnt' respectively
|
def __init__(self, cnt, cuplist=''): # files named 'Contents.cnt' and 'CupList' respectively
|
||||||
self.cuplist = cuplist
|
|
||||||
self.cnt = cnt
|
self.cnt = cnt
|
||||||
|
self.cuplist = 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))
|
|
||||||
|
|
||||||
files = {}
|
files = {}
|
||||||
for i in range(len(tidlist)):
|
|
||||||
files[f'{tidlist[i]}.cia'] = {
|
if self.cuplist != '':
|
||||||
'size': self.cnt_hdr.content_records[i].offset_end - self.cnt_hdr.content_records[i].offset,
|
with open(cuplist, 'rb') as f:
|
||||||
'offset': self.cnt_hdr.content_records[i].offset + 0x1400 - 2048
|
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
|
self.files = files
|
||||||
|
|
||||||
def extract(self):
|
def extract(self):
|
||||||
@ -68,6 +83,12 @@ class cntReader:
|
|||||||
for data in read_chunks(f, info['size']):
|
for data in read_chunks(f, info['size']):
|
||||||
g.write(data)
|
g.write(data)
|
||||||
g.close()
|
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()
|
f.close()
|
||||||
print(f'Extracted to {output_dir}')
|
print(f'Extracted to {output_dir}')
|
2
utils.py
2
utils.py
@ -669,7 +669,7 @@ def csu2retailcias(path, out=''):
|
|||||||
romfs = RomFSReader('romfs.bin')
|
romfs = RomFSReader('romfs.bin')
|
||||||
romfs.extract()
|
romfs.extract()
|
||||||
|
|
||||||
cnt = cntReader('romfs/contents/CupList', 'romfs/contents/Contents.cnt')
|
cnt = cntReader('romfs/contents/Contents.cnt', 'romfs/contents/CupList')
|
||||||
cnt.extract()
|
cnt.extract()
|
||||||
|
|
||||||
for i in ['cci_header.bin', 'card_info.bin', 'mastering_info.bin', 'initialdata.bin', 'card_device_info.bin', 'content0.game.ncch', 'ncch_header.bin', 'exheader.bin', 'logo.bin', 'plain.bin', 'exefs.bin', 'romfs.bin']:
|
for i in ['cci_header.bin', 'card_info.bin', 'mastering_info.bin', 'initialdata.bin', 'card_device_info.bin', 'content0.game.ncch', 'ncch_header.bin', 'exheader.bin', 'logo.bin', 'plain.bin', 'exefs.bin', 'romfs.bin']:
|
||||||
|
Loading…
Reference in New Issue
Block a user