1
0
Fork 0
mirror of https://github.com/DarkMatterCore/nxdumptool.git synced 2024-11-23 02:36:41 +00:00

Merging attempt; do not run

This commit is contained in:
bilditup1 2023-12-04 18:57:10 -05:00
commit 62fd26b622
15 changed files with 329 additions and 155 deletions

7
.gitignore vendored
View file

@ -1,9 +1,10 @@
.vscode
build
host/__pycache__
host/installer
host/build
host/dist
host/standalone
host/nxdt_host.build
host/nxdt_host.dist
host/nxdt_host.onefile-build
host/nxdumptool
*.elf
*.nacp

View file

@ -43,6 +43,7 @@ typedef bool (*MenuElementFunction)(void *userdata);
typedef struct {
u32 selected; ///< Used to keep track of the selected option.
bool retrieved; ///< Used to determine if the value for this option has already been retrieved from configuration.
MenuElementOptionGetterFunction getter_func; ///< Pointer to a function to be called the first time an option value is loaded. Should be set to NULL if not used.
MenuElementOptionSetterFunction setter_func; ///< Pointer to a function to be called each time a new option value is selected. Should be set to NULL if not used.
char **options; ///< Pointer to multiple char pointers with strings representing options. Last element must be set to NULL.
@ -147,6 +148,7 @@ static void consolePrintReversedColors(const char *text, ...);
static void consoleRefresh(void);
static u32 menuGetElementCount(const Menu *menu);
static void menuResetAttributes(Menu *cur_menu, u32 element_count);
void freeStorageList(void);
void updateStorageList(void);
@ -177,6 +179,8 @@ static char *generateOutputLayeredFsFileName(u64 title_id, const char *subdir, c
static bool dumpGameCardSecurityInformation(GameCardSecurityInformation *out);
static bool resetSettings(void *userdata);
static bool saveGameCardImage(void *userdata);
static bool saveGameCardHeader(void *userdata);
static bool saveGameCardCardInfo(void *userdata);
@ -289,6 +293,7 @@ static char **g_storageOptions = NULL;
static MenuElementOption g_storageMenuElementOption = {
.selected = 0,
.retrieved = false,
.getter_func = &getOutputStorageOption,
.setter_func = &setOutputStorageOption,
.options = NULL // Dynamically set
@ -316,6 +321,7 @@ static MenuElement *g_xciMenuElements[] = {
.task_func = NULL,
.element_options = &(MenuElementOption){
.selected = 0,
.retrieved = false,
.getter_func = &getGameCardPrependKeyAreaOption,
.setter_func = &setGameCardPrependKeyAreaOption,
.options = g_noYesStrings
@ -328,6 +334,7 @@ static MenuElement *g_xciMenuElements[] = {
.task_func = NULL,
.element_options = &(MenuElementOption){
.selected = 0,
.retrieved = false,
.getter_func = &getGameCardKeepCertificateOption,
.setter_func = &setGameCardKeepCertificateOption,
.options = g_noYesStrings
@ -340,6 +347,7 @@ static MenuElement *g_xciMenuElements[] = {
.task_func = NULL,
.element_options = &(MenuElementOption){
.selected = 0,
.retrieved = false,
.getter_func = &getGameCardTrimDumpOption,
.setter_func = &setGameCardTrimDumpOption,
.options = g_noYesStrings
@ -352,6 +360,7 @@ static MenuElement *g_xciMenuElements[] = {
.task_func = NULL,
.element_options = &(MenuElementOption){
.selected = 1,
.retrieved = false,
.getter_func = &getGameCardCalculateChecksumOption,
.setter_func = &setGameCardCalculateChecksumOption,
.options = g_noYesStrings
@ -410,6 +419,7 @@ static MenuElement *g_gameCardHfsMenuElements[] = {
.task_func = NULL,
.element_options = &(MenuElementOption){
.selected = 0,
.retrieved = false,
.getter_func = &getGameCardWriteRawHfsPartitionOption,
.setter_func = &setGameCardWriteRawHfsPartitionOption,
.options = g_noYesStrings
@ -514,6 +524,7 @@ static MenuElement *g_nspMenuElements[] = {
.task_func = NULL,
.element_options = &(MenuElementOption){
.selected = 0,
.retrieved = false,
.getter_func = &getNspSetDownloadDistributionOption,
.setter_func = &setNspSetDownloadDistributionOption,
.options = g_noYesStrings
@ -526,6 +537,7 @@ static MenuElement *g_nspMenuElements[] = {
.task_func = NULL,
.element_options = &(MenuElementOption){
.selected = 0,
.retrieved = false,
.getter_func = &getNspRemoveConsoleDataOption,
.setter_func = &setNspRemoveConsoleDataOption,
.options = g_noYesStrings
@ -538,6 +550,7 @@ static MenuElement *g_nspMenuElements[] = {
.task_func = NULL,
.element_options = &(MenuElementOption){
.selected = 0,
.retrieved = false,
.getter_func = &getNspRemoveTitlekeyCryptoOption,
.setter_func = &setNspRemoveTitlekeyCryptoOption,
.options = g_noYesStrings
@ -550,6 +563,7 @@ static MenuElement *g_nspMenuElements[] = {
.task_func = NULL,
.element_options = &(MenuElementOption){
.selected = 1,
.retrieved = false,
.getter_func = &getNspDisableLinkedAccountRequirementOption,
.setter_func = &setNspDisableLinkedAccountRequirementOption,
.options = g_noYesStrings
@ -562,6 +576,7 @@ static MenuElement *g_nspMenuElements[] = {
.task_func = NULL,
.element_options = &(MenuElementOption){
.selected = 1,
.retrieved = false,
.getter_func = &getNspEnableScreenshotsOption,
.setter_func = &setNspEnableScreenshotsOption,
.options = g_noYesStrings
@ -574,6 +589,7 @@ static MenuElement *g_nspMenuElements[] = {
.task_func = NULL,
.element_options = &(MenuElementOption){
.selected = 1,
.retrieved = false,
.getter_func = &getNspEnableVideoCaptureOption,
.setter_func = &setNspEnableVideoCaptureOption,
.options = g_noYesStrings
@ -586,6 +602,7 @@ static MenuElement *g_nspMenuElements[] = {
.task_func = NULL,
.element_options = &(MenuElementOption){
.selected = 1,
.retrieved = false,
.getter_func = &getNspDisableHdcpOption,
.setter_func = &setNspDisableHdcpOption,
.options = g_noYesStrings
@ -598,6 +615,7 @@ static MenuElement *g_nspMenuElements[] = {
.task_func = NULL,
.element_options = &(MenuElementOption){
.selected = 1,
.retrieved = false,
.getter_func = &getNspGenerateAuthoringToolDataOption,
.setter_func = &setNspGenerateAuthoringToolDataOption,
.options = g_noYesStrings
@ -630,6 +648,7 @@ static MenuElement *g_ticketMenuElements[] = {
.task_func = NULL,
.element_options = &(MenuElementOption){
.selected = 0,
.retrieved = false,
.getter_func = &getTicketRemoveConsoleDataOption,
.setter_func = &setTicketRemoveConsoleDataOption,
.options = g_noYesStrings
@ -653,6 +672,7 @@ static char **g_ncaBasePatchOptions = NULL;
static MenuElementOption g_ncaFsSectionsSubMenuBasePatchElementOption = {
.selected = 0,
.retrieved = false,
.getter_func = NULL,
.setter_func = NULL,
.options = NULL // Dynamically set
@ -679,6 +699,7 @@ static MenuElement *g_ncaFsSectionsSubMenuElements[] = {
.task_func = NULL,
.element_options = &(MenuElementOption){
.selected = 0,
.retrieved = false,
.getter_func = &getNcaFsWriteRawSectionOption,
.setter_func = &setNcaFsWriteRawSectionOption,
.options = g_noYesStrings
@ -691,6 +712,7 @@ static MenuElement *g_ncaFsSectionsSubMenuElements[] = {
.task_func = NULL,
.element_options = &(MenuElementOption){
.selected = 0,
.retrieved = false,
.getter_func = &getNcaFsUseLayeredFsDirOption,
.setter_func = &setNcaFsUseLayeredFsDirOption,
.options = g_noYesStrings
@ -869,6 +891,13 @@ static MenuElement *g_rootMenuElements[] = {
.element_options = NULL,
.userdata = NULL
},
&(MenuElement){
.str = "reset settings",
.child_menu = NULL,
.task_func = &resetSettings,
.element_options = NULL,
.userdata = NULL
},
NULL
};
@ -941,6 +970,7 @@ int main(int argc, char *argv[])
consolePrint("______________________________\n\n");
if (cur_menu->parent) consolePrint("press b to go back\n");
if (g_umsDeviceCount) consolePrint("press x to safely remove all ums devices\n");
consolePrint("use the sticks to scroll faster\n");
consolePrint("press + to exit\n");
consolePrint("______________________________\n\n");
@ -1032,10 +1062,10 @@ int main(int argc, char *argv[])
if (cur_options)
{
if (cur_options->getter_func)
if (cur_options->getter_func && !cur_options->retrieved)
{
cur_options->selected = cur_options->getter_func();
cur_options->getter_func = NULL;
cur_options->retrieved = true;
}
consolePrint(": ");
@ -1179,7 +1209,6 @@ int main(int argc, char *argv[])
if (!error)
{
child_menu->parent = cur_menu;
child_menu->selected = child_menu->scroll = 0;
cur_menu = child_menu;
element_count = menuGetElementCount(cur_menu);
@ -1200,23 +1229,29 @@ int main(int argc, char *argv[])
break;
}
/* Wait for USB session (if needed). */
if (useUsbHost() && !waitForUsb())
if (cur_menu->id > MenuId_Root)
{
if (g_appletStatus) continue;
break;
/* Wait for USB session (if needed). */
if (useUsbHost() && !waitForUsb())
{
if (g_appletStatus) continue;
break;
}
/* Run task. */
utilsSetLongRunningProcessState(true);
if (selected_element->task_func(selected_element->userdata))
{
if (!useUsbHost()) updateStorageList(); // update free space
}
utilsSetLongRunningProcessState(false);
} else {
/* Ignore result. */
selected_element->task_func(selected_element->userdata);
}
/* Run task. */
utilsSetLongRunningProcessState(true);
if (selected_element->task_func(selected_element->userdata))
{
if (!useUsbHost()) updateStorageList(); // update free space
}
utilsSetLongRunningProcessState(false);
/* Display prompt. */
consolePrint("press any button to continue");
utilsWaitForButtonPress(0);
@ -1302,6 +1337,8 @@ int main(int argc, char *argv[])
} else
if ((btn_down & HidNpadButton_B) && cur_menu->parent)
{
menuResetAttributes(cur_menu, element_count);
if (cur_menu->id == MenuId_UserTitles || cur_menu->id == MenuId_SystemTitles)
{
app_metadata = NULL;
@ -1344,9 +1381,6 @@ int main(int argc, char *argv[])
freeNcaBasePatchList();
}
cur_menu->selected = 0;
cur_menu->scroll = 0;
cur_menu = cur_menu->parent;
element_count = menuGetElementCount(cur_menu);
} else
@ -1483,6 +1517,21 @@ static u32 menuGetElementCount(const Menu *menu)
return cnt;
}
static void menuResetAttributes(Menu *cur_menu, u32 element_count)
{
if (!cur_menu) return;
cur_menu->selected = 0;
cur_menu->scroll = 0;
for(u32 i = 0; i < element_count; i++)
{
MenuElement *cur_element = cur_menu->elements[i];
MenuElementOption *cur_options = cur_element->element_options;
if (cur_options && cur_options != &g_storageMenuElementOption) cur_options->retrieved = false;
}
}
void freeStorageList(void)
{
u32 elem_count = (2 + g_umsDeviceCount); // sd card, usb host, ums devices
@ -1638,7 +1687,12 @@ end:
static TitleInfo *getLatestTitleInfo(TitleInfo *title_info, u32 *out_idx, u32 *out_count)
{
if (!title_info || !out_idx || !out_count || (title_info->meta_key.type != NcmContentMetaType_Patch && title_info->meta_key.type != NcmContentMetaType_DataPatch)) return title_info;
if (!title_info || !out_idx || !out_count || (title_info->meta_key.type != NcmContentMetaType_Patch && title_info->meta_key.type != NcmContentMetaType_DataPatch))
{
if (out_idx) *out_idx = 0;
if (out_count) *out_count = titleGetCountFromInfoBlock(title_info);
return title_info;
}
u32 idx = 0, count = 1;
TitleInfo *cur_info = title_info->previous, *out = title_info;
@ -2241,6 +2295,21 @@ static bool dumpGameCardSecurityInformation(GameCardSecurityInformation *out)
return true;
}
static bool resetSettings(void *userdata)
{
consolePrint("are you sure you want to reset all settings to their default values?\n");
consolePrint("press a to proceed, or b to cancel\n\n");
u64 btn_down = utilsWaitForButtonPress(HidNpadButton_A | HidNpadButton_B);
if (btn_down & HidNpadButton_A)
{
configResetSettings();
consolePrint("settings successfully reset\n");
}
return false;
}
static bool saveGameCardImage(void *userdata)
{
(void)userdata;
@ -4964,8 +5033,19 @@ static void nspThreadFunc(void *arg)
consolePrintReversedColors("\nif you proceed, nca modifications will be disabled, and content decryption");
consolePrintReversedColors("\nwill not be possible for external tools (e.g. emulators, etc.)\n");
consolePrintReversedColors("\nif this is a shared game and you wish to fix this, exit the application and");
consolePrintReversedColors("\ntry running it at least once, then come back and try again\n");
consolePrintReversedColors("\nthis may occur because of different reasons:\n");
consolePrintReversedColors("\n1. you haven't launched this game/dlc at least once since you downloaded it");
consolePrintReversedColors("\n2. this is a shared game/dlc across different switch consoles using the");
consolePrintReversedColors("\n same nintendo account and you're using the secondary console");
consolePrintReversedColors("\n3. you downloaded this game/dlc onto your sd card using your sysmmc, then");
consolePrintReversedColors("\n copied the 'nintendo' folder data into the 'emummc' folder (or viceversa)\n");
consolePrintReversedColors("\ncases 1 and 2 can be fixed by exiting nxdumptool, launching the game");
consolePrintReversedColors("\nand then running nxdumptool once again\n");
consolePrintReversedColors("\ncase 3 can be fixed by running nxdumptool directly under the emmc that was");
consolePrintReversedColors("\nused to download the game/dlc\n");
consolePrintReversedColors("\npress a to proceed anyway, or b to cancel\n\n");

View file

@ -7,8 +7,11 @@
from subprocess import run
from os.path import dirname, join
from sys import executable
from platform import system
root_dir = dirname(__file__)
run([executable, '-m', 'pip', 'install', '-r', join(root_dir, 'requirements-win32.txt')])
requirements_file = ('requirements-win32.txt' if system() == 'Windows' else 'requirements.txt')
run([executable, '-m', 'pip', 'install', '-r', join(root_dir, requirements_file)])
input('Press enter to close')

View file

@ -58,7 +58,7 @@ from tqdm import tqdm
from argparse import ArgumentParser, RawTextHelpFormatter, ArgumentDefaultsHelpFormatter
from io import BufferedWriter
from typing import List, Tuple, Any, Callable, Optional
from typing import Generator, Any, Callable
from datetime import datetime
@ -149,8 +149,8 @@ SERVER_START_MSG = f'Please connect a Nintendo Switch console running {USB_DEV_P
SERVER_STOP_MSG = f'Exit {USB_DEV_PRODUCT} on your console or disconnect it at any time to stop the server.'
# Default directory paths.
INITIAL_DIR = os.path.abspath(os.path.dirname(sys.executable if getattr(sys, 'frozen', False) else __file__))
DEFAULT_DIR = (INITIAL_DIR + os.path.sep + USB_DEV_PRODUCT)
INITIAL_DIR = os.path.dirname(os.path.abspath(os.path.expanduser(os.path.expandvars(sys.argv[0]))))
DEFAULT_DIR = os.path.join(INITIAL_DIR, USB_DEV_PRODUCT)
# Application icon (PNG).
# Embedded to load it as the icon for all windows using PhotoImage (which doesn't support ICO files) + wm_iconphoto.
@ -237,7 +237,7 @@ APP_ICON = b'iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAAAAR
b'43EDnoiNHI8a8FRs5HjMgCdjI8cj7+rp2MhR/Z3p7b5gyzRyjN0ei80cwP+bQrjkWSh1LgAAAABJRU5ErkJggg=='
# Taskbar Type Library (TLB). Used under Windows 7 or greater.
TASKBAR_LIB_PATH = (INITIAL_DIR + os.path.sep + 'TaskbarLib.tlb')
TASKBAR_LIB_PATH = os.path.join(INITIAL_DIR, 'TaskbarLib.tlb')
TASKBAR_LIB = b'TVNGVAIAAQAAAAAACQQAAAAAAABBAAAAAQAAAAAAAAAOAAAA/////wAAAAAAAAAATgAAADMDAAAAAAAA/////xgAAAAgAAAAgAAAAP////8AAAAAAAAAAGQAAADIAAAA' + \
b'LAEAAJABAAD0AQAAWAIAALwCAAAgAwAAhAMAAOgDAABMBAAAsAQAABQFAAB8AQAAeAUAAP////8PAAAA/////wAAAAD/////DwAAAP////8AAAAA/////w8AAABMCAAA' + \
@ -318,11 +318,11 @@ g_logToFile: bool = False
g_logVerbose: bool = False
g_terminalColors: bool = False
g_outputDir: str = ''
g_logLevelIntVar: tk.IntVar | None = None
g_logToFileBoolVar: tk.BooleanVar | None = None
g_logPath: str = ''
g_pathSep: str = ''
g_logLevelIntVar: tk.IntVar | None = None
g_logToFileBoolVar: tk.BooleanVar | None = None
g_osType: str = ''
g_osVersion: str = ''
@ -331,18 +331,18 @@ g_isWindowsVista: bool = False
g_isWindows7: bool = False
g_isWindows10: bool = False
g_tkRoot: Optional[tk.Tk] = None
g_tkCanvas: Optional[tk.Canvas] = None
g_tkDirText: Optional[tk.Text] = None
g_tkChooseDirButton: Optional[tk.Button] = None
g_tkServerButton: Optional[tk.Button] = None
g_tkTipMessage: Any = None
g_tkScrolledTextLog: Optional[scrolledtext.ScrolledText] = None
g_tkVerboseCheckbox: Optional[tk.Checkbutton] = None
g_tkRoot: tk.Tk | None = None
g_tkCanvas: tk.Canvas | None = None
g_tkDirText: tk.Text | None = None
g_tkChooseDirButton: tk.Button | None = None
g_tkServerButton: tk.Button | None = None
g_tkTipMessage: int = 0
g_tkScrolledTextLog: scrolledtext.ScrolledText | None = None
g_tkVerboseCheckbox: tk.Checkbutton | None = None
g_logger: Optional[logging.Logger] = None
g_logger: logging.Logger | None = None
g_stopEvent: Optional[threading.Event] = None
g_stopEvent: threading.Event | None = None
g_tlb: Any = None
g_taskbar: Any = None
@ -363,7 +363,7 @@ g_nspTransferMode: bool = False
g_nspSize: int = 0
g_nspHeaderSize: int = 0
g_nspRemainingSize: int = 0
g_nspFile: Optional[BufferedWriter] = None
g_nspFile: BufferedWriter | None = None
g_nspFilePath: str = ''
g_extractedFsDumpMode: bool = False
@ -378,7 +378,7 @@ g_extractedFsAbsRoot: str = ""
# Reference: https://beenje.github.io/blog/posts/logging-to-a-tkinter-scrolledtext-widget.
class LogQueueHandler(logging.Handler):
def __init__(self, log_queue: queue.Queue):
def __init__(self, log_queue: queue.Queue) -> None:
super().__init__()
self.log_queue = log_queue
@ -481,7 +481,7 @@ class LogConsole:
class ProgressBarWindow:
global g_tlb, g_taskbar
def __init__(self, bar_format: str = '', tk_parent: Any = None, window_title: str = '', window_resize: bool = False, window_protocol: Optional[Callable] = None):
def __init__(self, bar_format: str = '', tk_parent: Any = None, window_title: str = '', window_resize: bool = False, window_protocol: Callable | None = None) -> None:
self.n: int = 0
self.total: int = 0
self.divider: float = 1.0
@ -496,11 +496,11 @@ class ProgressBarWindow:
self.tk_parent = tk_parent
self.tk_window = (tk.Toplevel(self.tk_parent) if self.tk_parent else None)
self.withdrawn = False
self.tk_text_var: Optional[tk.StringVar] = None
self.tk_n_var: Optional[tk.DoubleVar] = None
self.tk_pbar: Optional[ttk.Progressbar] = None
self.tk_text_var: tk.StringVar | None = None
self.tk_n_var: tk.DoubleVar | None = None
self.tk_pbar: ttk.Progressbar | None = None
self.pbar: Optional[tqdm] = None
self.pbar: tqdm | None = None
if self.tk_window:
self.tk_window.withdraw()
@ -526,8 +526,8 @@ class ProgressBarWindow:
self.tk_pbar.configure(maximum=100, mode='indeterminate')
self.tk_pbar.pack()
def __del__(self):
if self.tk_parent:
def __del__(self) -> None:
if self.tk_window:
self.tk_parent.after(0, self.tk_window.destroy)
def start(self, total: int, n: int = 0, divider: int = 1, prefix: str = '', unit: str = 'B') -> None:
@ -619,7 +619,7 @@ class ProgressBarWindow:
def set_prefix(self, prefix) -> None:
self.prefix = prefix
g_progressBarWindow: Optional[ProgressBarWindow] = None
g_progressBarWindow: ProgressBarWindow | None = None
def eprint(*args, **kwargs) -> None:
print(*args, file=sys.stderr, **kwargs)
@ -747,7 +747,7 @@ def utilsResetNspInfo(delete: bool = False) -> None:
g_nspFile = None
g_nspFilePath = ''
def utilsGetSizeUnitAndDivisor(size: int) -> Tuple[str, int]:
def utilsGetSizeUnitAndDivisor(size: int) -> tuple[str, int]:
size_suffixes = [ 'B', 'KiB', 'MiB', 'GiB' ]
size_suffixes_count = len(size_suffixes)
@ -773,9 +773,10 @@ def usbGetDeviceEndpoints() -> bool:
global g_usbEpIn, g_usbEpOut, g_usbEpMaxPacketSize, g_usbVer
assert g_logger is not None
# assert g_stopEvent is not None
assert g_stopEvent is not None
prev_dev = cur_dev = None
cur_dev: Generator[usb.core.Device, Any, None] | None = None
prev_dev: usb.core.Device | None = None
usb_ep_in_lambda = lambda ep: usb.util.endpoint_direction(ep.bEndpointAddress) == usb.util.ENDPOINT_IN
usb_ep_out_lambda = lambda ep: usb.util.endpoint_direction(ep.bEndpointAddress) == usb.util.ENDPOINT_OUT
usb_version = 0
@ -791,8 +792,20 @@ def usbGetDeviceEndpoints() -> bool:
# Find a connected USB device with a matching VID/PID pair.
# Using == here to compare both device instances would also compare the backend, so we'll just compare certain elements manually.
cur_dev = usb.core.find(idVendor=USB_DEV_VID, idProduct=USB_DEV_PID)
if (cur_dev is None) or ((prev_dev is not None) and (cur_dev.bus == prev_dev.bus) and (cur_dev.address == prev_dev.address)):
try:
cur_dev = usb.core.find(find_all=False, idVendor=USB_DEV_VID, idProduct=USB_DEV_PID)
except:
if not g_cliMode:
utilsLogException(traceback.format_exc())
g_logger.error('\nFatal error ocurred while enumerating USB devices.')
if g_isWindows:
g_logger.error('\nTry reinstalling the libusbK driver using Zadig.')
return False
if (not isinstance(cur_dev, usb.core.Device)) or (isinstance(prev_dev, usb.core.Device) and (cur_dev.bus == prev_dev.bus) and (cur_dev.address == prev_dev.address)):
time.sleep(0.1)
continue
@ -846,6 +859,7 @@ def usbRead(size: int, timeout: int = -1) -> bytes:
except usb.core.USBError:
if not g_cliMode:
utilsLogException(traceback.format_exc())
if g_logger is not None:
g_logger.error('\nUSB timeout triggered or console disconnected.')
@ -859,13 +873,14 @@ def usbWrite(data: bytes, timeout: int = -1) -> int:
except usb.core.USBError:
if not g_cliMode:
utilsLogException(traceback.format_exc())
if g_logger is not None:
g_logger.error('\nUSB timeout triggered or console disconnected.')
return wr
def usbSendStatus(code: int) -> bool:
status = struct.pack('<4sIH6p', USB_MAGIC_WORD, code, g_usbEpMaxPacketSize, b'')
status = struct.pack('<4sIH6x', USB_MAGIC_WORD, code, g_usbEpMaxPacketSize)
return bool(usbWrite(status, USB_TRANSFER_TIMEOUT) == len(status))
def usbHandleStartSession(cmd_block: bytes) -> int:
@ -1020,6 +1035,7 @@ def usbHandleSendFileProperties(cmd_block: bytes) -> int | None:
if (not g_nspTransferMode) or (g_nspFile is None):
# Generate full, absolute path to the destination file.
fullpath = os.path.abspath(g_outputDir + os.path.sep + filename)
printable_fullpath = (fullpath[4:] if g_isWindows else fullpath)
printable_fullpath = (fullpath[4:] if g_isWindows else fullpath)
@ -1036,11 +1052,11 @@ def usbHandleSendFileProperties(cmd_block: bytes) -> int | None:
# Make sure the output filepath doesn't point to an existing directory.
if os.path.exists(fullpath) and (not os.path.isfile(fullpath)):
utilsResetNspInfo()
g_logger.error(f'\nOutput filepath points to an existing directory! ("{printable_fullpath}").\n')
g_logger.error(f'Output filepath points to an existing directory! ("{printable_fullpath}").\n')
return USB_STATUS_HOST_IO_ERROR
# Make sure we have enough free space.
(total_space, used_space, free_space) = shutil.disk_usage(dirpath)
(_, _, free_space) = shutil.disk_usage(dirpath)
if free_space <= file_size:
utilsResetNspInfo()
g_logger.error('\nNot enough free space available in output volume!\n')
@ -1090,10 +1106,7 @@ def usbHandleSendFileProperties(cmd_block: bytes) -> int | None:
# We're not using dynamic tqdm prefixes under CLI mode.
prefix = ''
else:
idx = filename.rfind(os.path.sep)
prefix_filename = (filename[idx+1:] if (idx >= 0) else filename)
prefix = f'Current {file_type_str}: "{prefix_filename}".\n'
prefix = f'Current {file_type_str}: "{os.path.basename(filename)}".\n'
prefix += 'Use your console to cancel the file transfer if you wish to do so.'
if (not g_nspTransferMode) or g_nspRemainingSize == (g_nspSize - g_nspHeaderSize):
@ -1117,8 +1130,13 @@ def usbHandleSendFileProperties(cmd_block: bytes) -> int | None:
def cancelTransfer():
# Cancel file transfer.
utilsResetNspInfo(True)
if use_pbar:
if g_nspTransferMode:
utilsResetNspInfo(True)
else:
file.close()
os.remove(fullpath)
if use_pbar and (g_progressBarWindow is not None):
g_progressBarWindow.end()
# Start transfer process.
@ -1152,7 +1170,7 @@ def usbHandleSendFileProperties(cmd_block: bytes) -> int | None:
# Check if we're dealing with a CancelFileTransfer command.
if chunk_size == USB_CMD_HEADER_SIZE:
(magic, cmd_id, cmd_block_size) = struct.unpack_from('<4sII', chunk, 0)
(magic, cmd_id, _) = struct.unpack_from('<4sII', chunk, 0)
if (magic == USB_MAGIC_WORD) and (cmd_id == USB_CMD_CANCEL_FILE_TRANSFER):
# Cancel file transfer.
cancelTransfer()
@ -1259,8 +1277,7 @@ def usbHandleEndSession(cmd_block: bytes) -> int:
def usbHandleStartExtractedFsDump(cmd_block: bytes) -> int:
assert g_logger is not None
global g_isWindows, g_outputDir, g_extractedFsDumpMode, g_extractedFsAbsRoot, g_formattedFileSize, g_formattedFileUnit, g_fileSizeMiB, g_startTime
g_logger.debug(f'Received StartExtractedFsDump ({USB_CMD_START_EXTRACTED_FS_DUMP:02X}) command.')
if g_nspTransferMode:
@ -1310,7 +1327,6 @@ def usbHandleStartExtractedFsDump(cmd_block: bytes) -> int:
return USB_STATUS_SUCCESS
def usbHandleEndExtractedFsDump(cmd_block: bytes) -> int:
global g_extractedFsDumpMode, g_extractedFsAbsRoot
assert g_logger is not None
g_logger.debug(f'Received EndExtractedFsDump ({USB_CMD_END_EXTRACTED_FS_DUMP:02X}) command.')
g_logger.info(f'Finished extracted FS dump.')
@ -1422,10 +1438,25 @@ def uiStopServer() -> None:
def uiStartServer() -> None:
uiUpdateOutputDir()
# Set new log path for this session if logging to file is turned on.
if g_logToFile:
utilsUpdateLogPath()
assert g_tkDirText is not None
g_outputDir = g_tkDirText.get('1.0', tk.END).strip()
if not g_outputDir:
# We should never reach this, honestly.
messagebox.showerror('Error', 'You must provide an output directory!', parent=g_tkRoot)
return
# Unconditionally enable 32-bit paths on Windows.
if g_isWindows:
g_outputDir = '\\\\?\\' + g_outputDir
# Make sure the full directory tree exists.
try:
os.makedirs(g_outputDir, exist_ok=True)
except:
utilsLogException(traceback.format_exc())
messagebox.showerror('Error', 'Unable to create full output directory tree!', parent=g_tkRoot)
return
# Update UI.
uiToggleElements(False)
@ -1442,7 +1473,6 @@ def uiToggleElements(flag: bool) -> None:
assert g_tkChooseDirButton is not None
assert g_tkServerButton is not None
assert g_tkCanvas is not None
assert g_tkLogToFileCheckbox is not None
assert g_tkVerboseCheckbox is not None
if flag:
@ -1529,11 +1559,7 @@ def uiHandleLogToFileCheckbox() -> None:
def uiHandleVerboseCheckbox() -> None:
assert g_logger is not None
assert g_logLevelIntVar is not None
global g_logVerbose
logLevel=g_logLevelIntVar.get()
g_logger.setLevel(logLevel)
g_logVerbose = True if(logLevel == logging.DEBUG) else False
return
g_logger.setLevel(g_logLevelIntVar.get())
def uiInitialize() -> None:
global SCALE, g_logLevelIntVar, g_logToFileBoolVar, g_logToFile, g_logVerbose
@ -1678,6 +1704,8 @@ def uiInitialize() -> None:
def cliInitialize() -> None:
global g_progressBarWindow, g_outputDir, g_logToFile
assert g_logger is not None
# Unconditionally enable long paths on Windows.
g_outputDir = utilsGetWinFullPath(g_outputDir) #if g_isWindows else g_outputDir
@ -1688,16 +1716,20 @@ def cliInitialize() -> None:
# NB, g_outputDir should be adjusted for Windows prior.
if g_logToFile:
utilsUpdateLogPath()
# Initialize console logger.
console = LogConsole()
# Initialize progress bar window object.
bar_format = '{percentage:.2f}% |{bar}| {n:.2f}/{total:.2f} [{elapsed}<{remaining}, {rate_fmt}]'
g_progressBarWindow = ProgressBarWindow(bar_format)
# Log basic info about the script and settings.
utilsLogBasicScriptInfo()
# Print info.
g_logger.info(f'\n{SCRIPT_TITLE}. {COPYRIGHT_TEXT}.')
g_logger.info(f'Output directory: "{g_outputDir}".\n')
# Unconditionally enable 32-bit paths on Windows.
if g_isWindows:
g_outputDir = '\\\\?\\' + g_outputDir
# Start USB command handler directly.
usbCommandHandler()
@ -1709,12 +1741,11 @@ def main() -> int:
warnings.filterwarnings("ignore")
# Parse command line arguments.
parser = ArgumentParser(formatter_class=RawTextHelpFormatter, description=SCRIPT_TITLE + '. ' + COPYRIGHT_TEXT + '.')
parser = ArgumentParser(description=SCRIPT_TITLE + '. ' + COPYRIGHT_TEXT + '.')
parser.add_argument('-c', '--cli', required=False, action='store_true', default=False, help='Start the script in CLI mode.')
parser.add_argument('-o', '--outdir', required=False, type=str, metavar='DIR', help='Path to output directory; will attempt to create if non-existent.'+\
'\nDefaults to "' + DEFAULT_DIR + '".')
parser.add_argument('-l', '--log', required=False, action='store_true', default=False, help='Enables logging to file in output directory in CLI mode.')
parser.add_argument('-o', '--outdir', required=False, type=str, metavar='DIR', help=f'Path to output directory. Defaults to "{DEFAULT_DIR}".')
parser.add_argument('-v', '--verbose', required=False, action='store_true', default=False, help='Enable verbose output.')
args = parser.parse_args()
# Update global flags.
@ -1766,9 +1797,7 @@ if __name__ == "__main__":
ret = main()
except KeyboardInterrupt:
time.sleep(0.2)
g_logger.info("Host script exited!")
if g_isWindows10: print(COLOR_RESET)
print('\nScript interrupted.')
except:
utilsLogException(traceback.format_exc())

View file

@ -3,26 +3,22 @@
set scriptdir=%~dp0
set scriptdir=%scriptdir:~0,-1%
set venvname=installer
set venvname=standalone
set venvscripts=%scriptdir%\%venvname%\Scripts
set venvpython=%venvscripts%\python.exe
set venvpyinstaller=%venvscripts%\pyinstaller.exe
cd /D "%scriptdir%"
python -m venv "%venvname%"
"%venvpython%" -m pip install --upgrade pyinstaller -r requirements-win32.txt
"%venvpython%" -m pip install --upgrade nuitka -r requirements-win32.txt
"%venvpyinstaller%" -y --clean --log-level WARN -F --add-binary "C:\Windows\System32\libusb0.dll;." -w -i nxdt.ico nxdt_host.py
"%venvpython%" -m nuitka --standalone --onefile --deployment --disable-console --windows-icon-from-ico=nxdt.ico --enable-plugin=tk-inter nxdt_host.py
move dist\nxdt_host.exe nxdt_host.exe
rmdir /s /q __pycache__
rmdir /s /q build
rmdir /s /q dist
rmdir /s /q installer
del nxdt_host.spec
rmdir /s /q nxdt_host.build
rmdir /s /q nxdt_host.dist
rmdir /s /q nxdt_host.onefile-build
rmdir /s /q standalone
pause

View file

@ -49,6 +49,9 @@ bool configInitialize(void);
/// Closes the configuration interface.
void configExit(void);
/// Resets settings to their default values.
void configResetSettings(void);
/// Getters and setters for various data types.
/// Path elements must be separated using forward slashes.

View file

@ -33,6 +33,8 @@ extern "C" {
#define SIGNED_TIK_MIN_SIZE sizeof(TikSigHmac160) /* Assuming no ESV1/ESV2 records are available. */
#define SIGNED_TIK_MAX_SIZE 0x400 /* Max ticket entry size in the ES ticket system savedata file. */
#define TIK_FORMAT_VERSION 2
#define GENERATE_TIK_STRUCT(sigtype, tiksize) \
typedef struct { \
SignatureBlock##sigtype sig_block; \
@ -72,7 +74,7 @@ typedef enum {
typedef struct {
char issuer[0x40];
u8 titlekey_block[0x100];
u8 format_version;
u8 format_version; ///< Always matches TIK_FORMAT_VERSION.
u8 titlekey_type; ///< TikTitleKeyType.
u16 ticket_version;
u8 license_type; ///< TikLicenseType.

View file

@ -133,6 +133,4 @@
#define DISCORD_SERVER_URL "https://discord.gg/SCbbcQx"
#define LOCKPICK_RCM_URL "https://github.com/shchmue/Lockpick_RCM"
#endif /* __DEFINES_H__ */

View file

@ -66,6 +66,7 @@ static struct json_object *g_configJson = NULL;
/* Function prototypes. */
static bool configParseConfigJson(void);
static bool configResetConfigJson(void);
static void configWriteConfigJson(void);
static void configFreeConfigJson(void);
@ -111,6 +112,11 @@ void configExit(void)
}
}
void configResetSettings(void)
{
configResetConfigJson();
}
CONFIG_GETTER(Boolean, bool);
CONFIG_SETTER(Boolean, bool);
@ -151,29 +157,36 @@ static bool configParseConfigJson(void)
jsonLogLastError();
}
if (use_default_config)
{
LOG_MSG_INFO("Loading default configuration.");
/* Free config JSON. */
configFreeConfigJson();
/* Read default config JSON. */
g_configJson = json_object_from_file(DEFAULT_CONFIG_PATH);
if (g_configJson)
{
configWriteConfigJson();
ret = true;
} else {
jsonLogLastError();
}
}
/* Try to load the default settings. */
if (use_default_config) ret = configResetConfigJson();
if (!ret) LOG_MSG_ERROR("Failed to parse both current and default JSON configuration files!");
return ret;
}
static bool configResetConfigJson(void)
{
bool ret = false;
LOG_MSG_INFO("Loading default configuration.");
/* Free config JSON. */
configFreeConfigJson();
/* Read default config JSON. */
g_configJson = json_object_from_file(DEFAULT_CONFIG_PATH);
if (g_configJson)
{
configWriteConfigJson();
ret = true;
} else {
jsonLogLastError();
}
return ret;
}
static void configWriteConfigJson(void)
{
if (!g_configJson) return;

View file

@ -28,7 +28,7 @@
#define GAMECARD_READ_BUFFER_SIZE 0x800000 /* 8 MiB. */
#define GAMECARD_ACCESS_DELAY 3 /* Seconds. */
#define GAMECARD_ACCESS_DELAY 3 /* Seconds. */
#define GAMECARD_UNUSED_AREA_BLOCK_SIZE 0x24
#define GAMECARD_UNUSED_AREA_SIZE(x) (((x) / GAMECARD_PAGE_SIZE) * GAMECARD_UNUSED_AREA_BLOCK_SIZE)
@ -134,7 +134,6 @@ static bool _gamecardGetDecryptedCardInfoArea(void);
static bool gamecardReadSecurityInformation(GameCardSecurityInformation *out);
static bool gamecardGetHandleAndStorage(u32 partition);
NX_INLINE void gamecardCloseHandle(void);
static bool gamecardOpenStorageArea(u8 area);
static bool gamecardReadStorageArea(void *out, u64 read_size, u64 offset);
@ -259,6 +258,12 @@ void gamecardExit(void)
g_gameCardReadBuf = NULL;
}
/* Make sure NS can access the gamecard. */
/* Fixes gamecard launch errors after exiting the application. */
/* TODO: find out why this doesn't work. */
//Result rc = nsEnsureGameCardAccess();
//if (R_FAILED(rc)) LOG_MSG_ERROR("nsEnsureGameCardAccess failed! (0x%X).", rc);
g_gameCardInterfaceInit = false;
}
}
@ -866,7 +871,7 @@ static bool gamecardReadHeader(void)
}
/* Read gamecard header. */
/* This step doesn't rely on gamecardReadStorageArea() because of its dependence on storage area sizes (which we haven't retrieved). */
/* We don't use gamecardReadStorageArea() here because of its dependence on storage area sizes (which we haven't yet retrieved). */
Result rc = fsStorageRead(&g_gameCardStorage, 0, &g_gameCardHeader, sizeof(GameCardHeader));
if (R_FAILED(rc))
{
@ -1000,7 +1005,6 @@ static bool gamecardGetHandleAndStorage(u32 partition)
rc = fsOpenGameCardStorage(&g_gameCardStorage, &g_gameCardHandle, partition);
if (R_FAILED(rc))
{
gamecardCloseHandle(); /* Close invalid gamecard handle. */
LOG_MSG_DEBUG("fsOpenGameCardStorage failed to open %s storage area on try #%u! (0x%X).", GAMECARD_STORAGE_AREA_NAME(partition + 1), i + 1, rc);
continue;
}
@ -1018,11 +1022,6 @@ static bool gamecardGetHandleAndStorage(u32 partition)
return R_SUCCEEDED(rc);
}
NX_INLINE void gamecardCloseHandle(void)
{
g_gameCardHandle.value = 0;
}
static bool gamecardOpenStorageArea(u8 area)
{
if (g_gameCardStatus < GameCardStatus_InsertedAndInfoNotLoaded || (area != GameCardStorageArea_Normal && area != GameCardStorageArea_Secure))
@ -1034,7 +1033,7 @@ static bool gamecardOpenStorageArea(u8 area)
/* Return right away if a valid handle has already been retrieved and the desired gamecard storage area is currently open. */
if (g_gameCardHandle.value && serviceIsActive(&(g_gameCardStorage.s)) && g_gameCardCurrentStorageArea == area) return true;
/* Close both gamecard handle and open storage area. */
/* Close both the gamecard handle and the open storage area. */
gamecardCloseStorageArea();
/* Retrieve both a new gamecard handle and a storage area handle. */
@ -1137,7 +1136,7 @@ static void gamecardCloseStorageArea(void)
memset(&g_gameCardStorage, 0, sizeof(FsStorage));
}
gamecardCloseHandle();
g_gameCardHandle.value = 0;
g_gameCardCurrentStorageArea = GameCardStorageArea_None;
}

View file

@ -202,7 +202,7 @@ bool utilsInitializeResources(const int program_argc, const char **program_argv)
/* Load keyset. */
if (!keysLoadKeyset())
{
LOG_MSG_ERROR("Failed to load keyset!\nUpdate your keys file with Lockpick_RCM:\n" LOCKPICK_RCM_URL);
LOG_MSG_ERROR("Failed to load keyset!\nPlease update your keys file with Lockpick_RCM.\nYou can get an updated build at:" DISCORD_SERVER_URL);
break;
}

View file

@ -386,8 +386,9 @@ static bool tikFixTamperedCommonTicket(Ticket *tik)
TikCommonBlock *tik_common_block = NULL;
u32 sig_type = 0;
u8 *signature = NULL;
u64 signature_size = 0, hash_area_size = 0;
bool dev_cert = false;
TikSigRsa2048 *tik_data = NULL;
u64 hash_area_size = 0;
bool success = false;
@ -397,15 +398,23 @@ static bool tikFixTamperedCommonTicket(Ticket *tik)
return false;
}
/* Get ticket signature and its properties, as well as the ticket hash area size. */
/* Get ticket signature type. Also determine if it's a development ticket. */
sig_type = signatureGetTypeFromSignedBlob(tik->data, false);
signature = signatureGetSigFromSignedBlob(tik->data);
signature_size = signatureGetSigSizeByType(sig_type);
dev_cert = (strstr(tik_common_block->issuer, TIK_DEV_CERT_ISSUER) != NULL);
/* Return right away if we're not dealing with a common ticket or if the signature type doesn't match RSA-2048 + SHA-256. */
if (tik_common_block->titlekey_type != TikTitleKeyType_Common || sig_type != SignatureType_Rsa2048Sha256)
{
success = true;
goto end;
}
/* Make sure we're dealing with a tampered ticket by verifying its signature. */
tik_data = (TikSigRsa2048*)tik->data;
tik_common_block = &(tik_data->tik_common_block);
hash_area_size = tikGetSignedTicketBlobHashAreaSize(tik->data);
/* Return right away if we're not dealing with a common ticket, if the signature type doesn't match RSA-2048 + SHA-256, or if the signature is valid. */
if (tik_common_block->titlekey_type != TikTitleKeyType_Common || sig_type != SignatureType_Rsa2048Sha256 || \
tikVerifyRsa2048Sha256Signature(tik_common_block, hash_area_size, signature))
if (tikVerifyRsa2048Sha256Signature(tik_common_block, hash_area_size, tik_data->sig_block.signature))
{
success = true;
goto end;
@ -416,22 +425,35 @@ static bool tikFixTamperedCommonTicket(Ticket *tik)
/* Nintendo didn't start putting the key generation value into the rights ID until HOS 3.0.1. */
/* Old custom tools used to wipe the key generation field and/or save its value into a different offset. */
/* We're gonna take care of that by setting the correct values where they need to go. */
memset(signature, 0xFF, signature_size);
memset(tik_data->sig_block.signature, 0xFF, sizeof(tik_data->sig_block.signature));
memset(tik_data->sig_block.padding, 0, sizeof(tik_data->sig_block.padding));
memset(tik_common_block->issuer, 0, sizeof(tik_common_block->issuer));
sprintf(tik_common_block->issuer, "Root-CA%08X-%s", dev_cert ? 4 : 3, TIK_COMMON_CERT_NAME);
memset(tik_common_block->titlekey_block + 0x10, 0, sizeof(tik_common_block->titlekey_block) - 0x10);
tik_common_block->format_version = TIK_FORMAT_VERSION;
tik_common_block->titlekey_type = TikTitleKeyType_Common;
tik_common_block->ticket_version = 0;
tik_common_block->license_type = TikLicenseType_Permanent;
tik_common_block->key_generation = tik->key_generation;
tik_common_block->property_mask = TikPropertyMask_None;
memset(tik_common_block->reserved, 0, sizeof(tik_common_block->reserved));
tik_common_block->ticket_id = 0;
tik_common_block->device_id = 0;
tik_common_block->account_id = 0;
tik_common_block->sect_total_size = 0;
tik_common_block->sect_hdr_offset = (u32)tik->size;
tik_common_block->sect_hdr_offset = (u32)sizeof(TikSigRsa2048);
tik_common_block->sect_hdr_count = 0;
tik_common_block->sect_hdr_entry_size = 0;
/* Update ticket size. */
tik->size = sizeof(TikSigRsa2048);
/* Update return value. */
success = true;
@ -447,8 +469,8 @@ static bool tikVerifyRsa2048Sha256Signature(const TikCommonBlock *tik_common_blo
return false;
}
const char *cert_name = (strrchr(tik_common_block->issuer, '-') + 1);
Certificate cert = {0};
const char *cert_name = (strrchr(tik_common_block->issuer, '-') + 1);
const u8 *modulus = NULL, *public_exponent = NULL;
/* Get certificate for the ticket signature issuer. */

View file

@ -552,7 +552,7 @@ static bool titleRetrieveUserApplicationMetadataByTitleId(u64 title_id, TitleApp
NX_INLINE TitleApplicationMetadata *titleFindApplicationMetadataByTitleId(u64 title_id, bool is_system, u32 extra_app_count);
NX_INLINE u64 titleGetApplicationIdByMetaKey(const NcmContentMetaKey *meta_key);
NX_INLINE u64 titleGetApplicationIdByContentMetaKey(const NcmContentMetaKey *meta_key);
static bool titleGenerateTitleInfoEntriesForTitleStorage(TitleStorage *title_storage);
static bool titleGetMetaKeysFromContentDatabase(NcmContentMetaDatabase *ncm_db, NcmContentMetaKey **out_meta_keys, u32 *out_meta_key_count);
@ -1026,6 +1026,7 @@ TitleInfo **titleGetOrphanTitles(u32 *out_count)
}
/* Allocate orphan title info pointer array. */
/* titleFreeOrphanTitles() depends on the last NULL element. */
orphan_info = calloc(g_orphanTitleInfoCount + 1, sizeof(TitleInfo*));
if (!orphan_info)
{
@ -1373,6 +1374,33 @@ NX_INLINE bool titleInitializePersistentTitleStorages(void)
}
}
#if LOG_LEVEL <= LOG_LEVEL_INFO
#define ORPHAN_INFO_LOG(fmt, ...) utilsAppendFormattedStringToBuffer(&orphan_info_buf, &orphan_info_buf_size, fmt, ##__VA_ARGS__)
if (g_orphanTitleInfo && g_orphanTitleInfoCount)
{
char *orphan_info_buf = NULL;
size_t orphan_info_buf_size = 0;
ORPHAN_INFO_LOG("Identified %u orphan title(s) across all initialized title storages.\r\n", g_orphanTitleInfoCount);
for(u32 i = 0; i < g_orphanTitleInfoCount; i++)
{
TitleInfo *orphan_info = g_orphanTitleInfo[i];
ORPHAN_INFO_LOG("- %016lX v%u (%s, %s).%s", orphan_info->meta_key.id, orphan_info->version.value, titleGetNcmContentMetaTypeName(orphan_info->meta_key.type), \
titleGetNcmStorageIdName(orphan_info->storage_id), (i + 1) < g_orphanTitleInfoCount ? "\r\n" : "");
}
if (orphan_info_buf)
{
LOG_MSG_INFO("%s", orphan_info_buf);
free(orphan_info_buf);
}
}
#undef ORPHAN_INFO_LOG
#endif /* LOG_LEVEL <= LOG_LEVEL_INFO */
return true;
}
@ -1861,7 +1889,7 @@ NX_INLINE TitleApplicationMetadata *titleFindApplicationMetadataByTitleId(u64 ti
return NULL;
}
NX_INLINE u64 titleGetApplicationIdByMetaKey(const NcmContentMetaKey *meta_key)
NX_INLINE u64 titleGetApplicationIdByContentMetaKey(const NcmContentMetaKey *meta_key)
{
if (!meta_key) return 0;
@ -1961,7 +1989,7 @@ static bool titleGenerateTitleInfoEntriesForTitleStorage(TitleStorage *title_sto
utilsGenerateFormattedSizeString((double)cur_title_info->size, cur_title_info->size_str, sizeof(cur_title_info->size_str));
/* Retrieve application metadata. */
u64 app_id = titleGetApplicationIdByMetaKey(&(cur_title_info->meta_key));
u64 app_id = titleGetApplicationIdByContentMetaKey(&(cur_title_info->meta_key));
cur_title_info->app_metadata = titleFindApplicationMetadataByTitleId(app_id, storage_id == NcmStorageId_BuiltInSystem, 0);
if (!cur_title_info->app_metadata && storage_id == NcmStorageId_BuiltInSystem)
{
@ -2203,7 +2231,7 @@ static void titleUpdateTitleInfoLinkedLists(void)
{
/* We're dealing with a patch, an add-on content or an add-on content patch. */
/* We'll just retrieve a pointer to the first matching user application entry and use it to set a pointer to an application metadata entry. */
u64 app_id = titleGetApplicationIdByMetaKey(&(child_info->meta_key));
u64 app_id = titleGetApplicationIdByContentMetaKey(&(child_info->meta_key));
TitleInfo *parent = _titleGetInfoFromStorageByTitleId(NcmStorageId_Any, app_id);
if (parent)
{
@ -2367,7 +2395,7 @@ static bool titleRefreshGameCardTitleInfo(void)
if (!cur_title_info) continue;
/* Do not proceed if application metadata has already been retrieved, or if we can successfully retrieve it. */
u64 app_id = titleGetApplicationIdByMetaKey(&(cur_title_info->meta_key));
u64 app_id = titleGetApplicationIdByContentMetaKey(&(cur_title_info->meta_key));
if (cur_title_info->app_metadata != NULL || (cur_title_info->app_metadata = titleFindApplicationMetadataByTitleId(app_id, false, extra_app_count)) != NULL) continue;
/* Retrieve application metadata pointer. */

View file

@ -160,7 +160,7 @@ enum usb_supported_speed {
};
/// Imported from libusb, with some adjustments.
struct PACKED usb_bos_descriptor {
struct NX_PACKED usb_bos_descriptor {
u8 bLength;
u8 bDescriptorType; ///< Must match USB_DT_BOS.
u16 wTotalLength; ///< Length of this descriptor and all of its sub descriptors.
@ -170,7 +170,7 @@ struct PACKED usb_bos_descriptor {
NXDT_ASSERT(struct usb_bos_descriptor, 0x5);
/// Imported from libusb, with some adjustments.
struct PACKED usb_2_0_extension_descriptor {
struct NX_PACKED usb_2_0_extension_descriptor {
u8 bLength;
u8 bDescriptorType; ///< Must match USB_DT_DEVICE_CAPABILITY.
u8 bDevCapabilityType; ///< Must match USB_BT_USB_2_0_EXTENSION.
@ -180,7 +180,7 @@ struct PACKED usb_2_0_extension_descriptor {
NXDT_ASSERT(struct usb_2_0_extension_descriptor, 0x7);
/// Imported from libusb, with some adjustments.
struct PACKED usb_ss_usb_device_capability_descriptor {
struct NX_PACKED usb_ss_usb_device_capability_descriptor {
u8 bLength;
u8 bDescriptorType; ///< Must match USB_DT_DEVICE_CAPABILITY.
u8 bDevCapabilityType; ///< Must match USB_BT_SS_USB_DEVICE_CAPABILITY.

View file

@ -92,7 +92,7 @@ namespace nxdt::utils {
}
#endif /* LOG_LEVEL < LOG_LEVEL_NONE */
static void NORETURN AbortProgramExecution(std::string str)
static void NX_NORETURN AbortProgramExecution(std::string str)
{
if (g_borealisInitialized)
{