mirror of
https://github.com/DarkMatterCore/nxdumptool.git
synced 2024-11-22 18:26:39 +00:00
Update to v1.1.9.
This commit is contained in:
parent
e475796676
commit
a999447580
20 changed files with 2459 additions and 2031 deletions
12
Makefile
12
Makefile
|
@ -33,13 +33,13 @@ include $(DEVKITPRO)/libnx/switch_rules
|
|||
|
||||
VERSION_MAJOR := 1
|
||||
VERSION_MINOR := 1
|
||||
VERSION_MICRO := 8
|
||||
VERSION_MICRO := 9
|
||||
|
||||
APP_TITLE := nxdumptool
|
||||
APP_AUTHOR := MCMrARM, DarkMatterCore
|
||||
APP_AUTHOR := DarkMatterCore
|
||||
APP_VERSION := ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_MICRO}
|
||||
|
||||
TARGET := nxdumptool
|
||||
TARGET := ${APP_TITLE}
|
||||
BUILD := build
|
||||
SOURCES := source source/fatfs
|
||||
DATA := data
|
||||
|
@ -52,10 +52,8 @@ ROMFS := romfs
|
|||
#---------------------------------------------------------------------------------
|
||||
ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE
|
||||
|
||||
CFLAGS := -g -Wall -Wno-address-of-packed-member -O2 -ffunction-sections \
|
||||
$(ARCH) $(DEFINES)
|
||||
|
||||
CFLAGS += $(INCLUDE) -D__SWITCH__ -D__LINUX_ERRNO_EXTENSIONS__ -DAPP_VERSION=\"${APP_VERSION}\"
|
||||
CFLAGS := -g -Wall -Wextra -O2 -ffunction-sections $(ARCH) $(DEFINES) $(INCLUDE) -D__SWITCH__
|
||||
CFLAGS += -DAPP_TITLE=\"${APP_TITLE}\" -DAPP_VERSION=\"${APP_VERSION}\"
|
||||
CFLAGS += `freetype-config --cflags`
|
||||
CFLAGS += `aarch64-none-elf-pkg-config zlib --cflags`
|
||||
CFLAGS += `aarch64-none-elf-pkg-config libxml-2.0 --cflags`
|
||||
|
|
26
README.md
26
README.md
|
@ -9,7 +9,7 @@ Nintendo Switch Dump Tool
|
|||
Main features
|
||||
--------------
|
||||
|
||||
* Generates full Cartridge Image dumps (XCI) with optional certificate removal and/or trimming.
|
||||
* Generates NX Card Image (XCI) dumps from the inserted gamecard, with optional certificate removal and/or trimming.
|
||||
* Generates installable Nintendo Submission Packages (NSP) from base applications, updates and DLCs stored in the inserted gamecard, SD card and eMMC storage devices.
|
||||
* The generated dumps follow the `AuditingTool` format from Scene releases.
|
||||
* Capable of generating dumps without console specific information (common ticket).
|
||||
|
@ -78,6 +78,30 @@ If you like my work and you'd like to support me in any way, it's not necessary,
|
|||
Changelog
|
||||
--------------
|
||||
|
||||
**v1.1.9:**
|
||||
|
||||
* Built using libnx commit d7e6207.
|
||||
* Removed unnecessary code in NSP dumping steps.
|
||||
* Improved GitHub JSON parsing code.
|
||||
* Added NSP/ExeFS/RomFS support for titles with multiple Program NCAs (populated ID offset fields). Big thanks to [Cirosan](https://github.com/Cirosan) and [ITotalJustice](https://github.com/ITotalJustice) for testing!
|
||||
* Fixed compatibility with consoles that use the new PRODINFO key generation scheme. Big thanks to dimitriblaiddyd78 from GBAtemp for reporting the issue and providing with testing!
|
||||
* Fixed ExeFS/RomFS browsing/dumping support for bundled-in game updates in gamecards.
|
||||
* Recursive directory removal after a failed HFS0/ExeFS/RomFS data dump is now optional.
|
||||
* Fixed RomFS section dump support for titles that hold enough files in a single directory to exceed the max file count per directory limit in FAT32 (e.g. Animal Crossing: New Horizons).
|
||||
* In order to overcome this problem, a secondary directory is created using the current RomFS directory name + a counter value (e.g. `/Model` -> `/Model_0`).
|
||||
* This directory is used to save the rest of the data from the current RomFS directory until:
|
||||
* All files from the current RomFS directory have been dumped, or...
|
||||
* The directory reaches the max file count as well and another directory must be created to continue the process (e.g. `/Model_0` -> `/Model_1`).
|
||||
* Big thanks to [Michael18751](https://github.com/Michael18751), [TechGeekGamer](https://github.com/TechGeekGamer) and [SusejLav](https://github.com/SusejLav) for testing!
|
||||
* Button presses are now retrieved from all connected controllers.
|
||||
* HOME button presses are now only blocked during dump operations. Fixes problems with homebrew forwarders and qlaunch replacements.
|
||||
* Additionally, long HOME button presses are now blocked as well.
|
||||
* Removed max entry count limit for HFS0/ExeFS/RomFS browsers. All filenames are now dynamically allocated, as it should have been from the very start.
|
||||
* Updated NACP struct to reflect latest discoveries made by [0Liam](https://github.com/0Liam).
|
||||
* The application now displays a FW update warning when the contents from an inserted gamecard can't be parsed because they use an unsupported NCA keygen. Thanks to [ITotalJustice](https://github.com/ITotalJustice) for spotting it!
|
||||
|
||||
This is only a bugfix release. I don't expect to release any new versions until the rewrite is finished - the only exception being fixing some kind of feature-breaking bug. Please understand.
|
||||
|
||||
**v1.1.8:**
|
||||
* Added compatibility with latest devkitA64 and libnx releases. Thanks to [HookedBehemoth](https://github.com/HookedBehemoth) for porting the extra IPC calls used by the application to the new IPC system!
|
||||
* Now using global title contexts instead of global variables for each different title property (ID, version, source storage, etc.). Simplifies metadata retrieval functions.
|
||||
|
|
1800
source/dumper.c
1800
source/dumper.c
File diff suppressed because it is too large
Load diff
|
@ -27,19 +27,21 @@ typedef struct {
|
|||
u32 certlessCrc; // CRC32 checksum accumulator (certless XCI). Only used if calcCrc == true
|
||||
} PACKED sequentialXciCtx;
|
||||
|
||||
// This struct is followed by 'ncaCount' SHA-256 checksums in the output file and 'programNcaModCount' modified + reencrypted Program NCA headers
|
||||
// The modified NCA headers are only needed if their NPDM signature is replaced (it uses cryptographically secure random numbers). The RSA public key used in the ACID section from the main.npdm file is constant, so we don't need to keep track of that
|
||||
typedef struct {
|
||||
NcmStorageId storageId; // Source storage from which the data is dumped
|
||||
NcmStorageId storageId; // Source storage from which the data is dumped
|
||||
bool removeConsoleData; // Original value for the "Remove console specific data" option. Overrides the selected setting in the current session
|
||||
bool tiklessDump; // Original value for the "Generate ticket-less dump" option. Overrides the selected setting in the current session. Ignored if removeConsoleData == false
|
||||
bool npdmAcidRsaPatch; // Original value for the "Change NPDM RSA key/sig in Program NCA" option. Overrides the selected setting in the current session
|
||||
bool preInstall; // Indicates if we're dealing with a preinstalled title - e.g. if the user already accepted the missing ticket prompt
|
||||
u8 partNumber; // Next part number
|
||||
u32 nspFileCount; // PFS0 file count
|
||||
u32 pfs0FileCount; // PFS0 file count
|
||||
u32 ncaCount; // NCA count
|
||||
u32 programNcaModCount; // Program NCA mod count
|
||||
u32 fileIndex; // Current PFS0 file entry index
|
||||
u64 fileOffset; // Current PFS0 file entry offset
|
||||
Sha256Context hashCtx; // Current NCA SHA-256 checksum context. Only used when dealing with the same NCA between different parts
|
||||
u8 programNcaHeaderMod[NCA_FULL_HEADER_LENGTH]; // Modified + reencrypted Program NCA header. Only needed if the NPDM signature in the Program NCA header is replaced (it uses cryptographically secure random numbers). The RSA public key used in the ACID section from the main.npdm file is constant, so we don't need to keep track of that
|
||||
} PACKED sequentialNspCtx;
|
||||
|
||||
typedef struct {
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#include <switch/arm/atomics.h>
|
||||
#include <switch/kernel/ipc.h>
|
||||
#include <switch/services/sm.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
|
|
@ -22,6 +22,8 @@ DSTATUS disk_status (
|
|||
BYTE pdrv /* Physical drive nmuber to identify the drive */
|
||||
)
|
||||
{
|
||||
(void)pdrv;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -35,6 +37,8 @@ DSTATUS disk_initialize (
|
|||
BYTE pdrv /* Physical drive nmuber to identify the drive */
|
||||
)
|
||||
{
|
||||
(void)pdrv;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -51,9 +55,15 @@ DRESULT disk_read (
|
|||
UINT count /* Number of sectors to read */
|
||||
)
|
||||
{
|
||||
if (R_SUCCEEDED(fsStorageRead(&fatFsStorage, FF_MAX_SS * sector, buff, FF_MAX_SS * count)))
|
||||
return RES_OK;
|
||||
return RES_ERROR;
|
||||
(void)pdrv;
|
||||
(void)buff;
|
||||
(void)sector;
|
||||
(void)count;
|
||||
|
||||
Result rc = fsStorageRead(&fatFsStorage, FF_MAX_SS * sector, buff, FF_MAX_SS * count);
|
||||
if (R_FAILED(rc)) return RES_ERROR;
|
||||
|
||||
return RES_OK;
|
||||
}
|
||||
|
||||
|
||||
|
@ -71,7 +81,12 @@ DRESULT disk_write (
|
|||
UINT count /* Number of sectors to write */
|
||||
)
|
||||
{
|
||||
return RES_PARERR;
|
||||
(void)pdrv;
|
||||
(void)buff;
|
||||
(void)sector;
|
||||
(void)count;
|
||||
|
||||
return RES_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -87,6 +102,10 @@ DRESULT disk_ioctl (
|
|||
void *buff /* Buffer to send/receive control data */
|
||||
)
|
||||
{
|
||||
(void)pdrv;
|
||||
(void)cmd;
|
||||
(void)buff;
|
||||
|
||||
return RES_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
#include <switch/kernel/ipc.h>
|
||||
#include <switch/services/fs.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
|
123
source/keys.c
123
source/keys.c
|
@ -8,7 +8,6 @@
|
|||
#include "util.h"
|
||||
#include "ui.h"
|
||||
#include "es.h"
|
||||
#include "set_ext.h"
|
||||
#include "save.h"
|
||||
|
||||
/* Extern variables */
|
||||
|
@ -24,7 +23,7 @@ extern char strbuf[NAME_BUF_LEN];
|
|||
|
||||
nca_keyset_t nca_keyset;
|
||||
|
||||
static u8 eticket_data[ETICKET_DEVKEY_DATA_SIZE];
|
||||
static SetCalRsa2048DeviceKey eticket_data;
|
||||
static bool setcal_eticket_retrieved = false;
|
||||
|
||||
static keyLocation FSRodata = {
|
||||
|
@ -553,45 +552,36 @@ static int get_kv(FILE *f, char **key, char **value)
|
|||
#undef SKIP_SPACE
|
||||
}
|
||||
|
||||
static int ishex(char c)
|
||||
{
|
||||
if ('a' <= c && c <= 'f') return 1;
|
||||
if ('A' <= c && c <= 'F') return 1;
|
||||
if ('0' <= c && c <= '9') return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char hextoi(char c)
|
||||
{
|
||||
if ('a' <= c && c <= 'f') return (c - 'a' + 0xA);
|
||||
if ('A' <= c && c <= 'F') return (c - 'A' + 0xA);
|
||||
if ('0' <= c && c <= '9') return (c - '0');
|
||||
return 0;
|
||||
return 'z';
|
||||
}
|
||||
|
||||
int parse_hex_key(unsigned char *key, const char *hex, unsigned int len)
|
||||
{
|
||||
if (strlen(hex) != (2 * len))
|
||||
{
|
||||
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: key (%s) must be %u hex digits!", __func__, hex, 2 * len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 i;
|
||||
for(i = 0; i < (2 * len); i++)
|
||||
size_t hex_str_len = (2 * len);
|
||||
|
||||
if (strlen(hex) != hex_str_len)
|
||||
{
|
||||
if (!ishex(hex[i]))
|
||||
{
|
||||
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: key (%s) must be %u hex digits!", __func__, hex, 2 * len);
|
||||
return 0;
|
||||
}
|
||||
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: key (%s) must be %u hex digits!", __func__, hex, hex_str_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(key, 0, len);
|
||||
|
||||
for(i = 0; i < (2 * len); i++)
|
||||
for(i = 0; i < hex_str_len; i++)
|
||||
{
|
||||
char val = hextoi(hex[i]);
|
||||
if (val == 'z')
|
||||
{
|
||||
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: key (%s) must be %u hex digits!", __func__, hex, hex_str_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((i & 1) == 0) val <<= 4;
|
||||
key[i >> 1] |= val;
|
||||
}
|
||||
|
@ -605,6 +595,7 @@ int readKeysFromFile(FILE *f)
|
|||
int ret;
|
||||
char *key, *value;
|
||||
char test_name[0x100];
|
||||
bool common_eticket = false, personalized_eticket = false;
|
||||
|
||||
while((ret = get_kv(f, &key, &value)) != 1 && ret != -2)
|
||||
{
|
||||
|
@ -612,15 +603,19 @@ int readKeysFromFile(FILE *f)
|
|||
{
|
||||
if (key == NULL || value == NULL) continue;
|
||||
|
||||
if (strcasecmp(key, "eticket_rsa_kek") == 0)
|
||||
if (!common_eticket && !personalized_eticket && strcasecmp(key, "eticket_rsa_kek") == 0)
|
||||
{
|
||||
if (!parse_hex_key(nca_keyset.eticket_rsa_kek, value, sizeof(nca_keyset.eticket_rsa_kek))) return 0;
|
||||
nca_keyset.ext_key_cnt++;
|
||||
common_eticket = true;
|
||||
} else
|
||||
if (strcasecmp(key, "save_mac_key") == 0)
|
||||
if (!personalized_eticket && strcasecmp(key, "eticket_rsa_kek_personalized") == 0)
|
||||
{
|
||||
if (!parse_hex_key(nca_keyset.save_mac_key, value, sizeof(nca_keyset.save_mac_key))) return 0;
|
||||
nca_keyset.ext_key_cnt++;
|
||||
/* Use the personalized eTicket RSA kek if available */
|
||||
/* This only appears on consoles that use the new PRODINFO key generation scheme */
|
||||
if (!parse_hex_key(nca_keyset.eticket_rsa_kek, value, sizeof(nca_keyset.eticket_rsa_kek))) return 0;
|
||||
if (!common_eticket) nca_keyset.ext_key_cnt++;
|
||||
personalized_eticket = true;
|
||||
} else {
|
||||
memset(test_name, 0, sizeof(test_name));
|
||||
|
||||
|
@ -768,6 +763,59 @@ void mgf1(const u8 *data, size_t data_length, u8 *mask, size_t mask_length)
|
|||
free(data_counter);
|
||||
}
|
||||
|
||||
void dumpSharedTikSavedata(void)
|
||||
{
|
||||
FRESULT fr;
|
||||
FIL save;
|
||||
u32 size, blk, i, j;
|
||||
u32 rd_b, wr_b;
|
||||
|
||||
FILE *out;
|
||||
|
||||
for(i = 0; i < 2; i++)
|
||||
{
|
||||
fr = FR_OK;
|
||||
memset(&save, 0, sizeof(FIL));
|
||||
size = 0;
|
||||
blk = DUMP_BUFFER_SIZE;
|
||||
|
||||
out = NULL;
|
||||
|
||||
fr = f_open(&save, (i == 0 ? "sys:/save/80000000000000e3" : "sys:/save/80000000000000e4"), FA_READ | FA_OPEN_EXISTING);
|
||||
if (fr) continue;
|
||||
|
||||
size = f_size(&save);
|
||||
if (!size)
|
||||
{
|
||||
f_close(&save);
|
||||
continue;
|
||||
}
|
||||
|
||||
out = fopen((i == 0 ? "sdmc:/80000000000000e3" : "sdmc:/80000000000000e4"), "wb");
|
||||
if (!out)
|
||||
{
|
||||
f_close(&save);
|
||||
continue;
|
||||
}
|
||||
|
||||
for(j = 0; j < size; j += blk)
|
||||
{
|
||||
if ((size - j) < blk) blk = (size - j);
|
||||
|
||||
rd_b = wr_b = 0;
|
||||
|
||||
fr = f_read(&save, dumpBuf, blk, &rd_b);
|
||||
if (fr || rd_b != blk) break;
|
||||
|
||||
wr_b = fwrite(dumpBuf, 1, blk, out);
|
||||
if (wr_b != blk) break;
|
||||
}
|
||||
|
||||
fclose(out);
|
||||
f_close(&save);
|
||||
}
|
||||
}
|
||||
|
||||
int retrieveNcaTikTitleKey(nca_header_t *dec_nca_header, u8 *out_tik, u8 *out_enc_key, u8 *out_dec_key)
|
||||
{
|
||||
int ret = -1;
|
||||
|
@ -936,6 +984,7 @@ int retrieveNcaTikTitleKey(nca_header_t *dec_nca_header, u8 *out_tik, u8 *out_en
|
|||
{
|
||||
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: NCA rights ID unavailable in this console!", __func__);
|
||||
ret = -2;
|
||||
dumpSharedTikSavedata();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -945,7 +994,7 @@ int retrieveNcaTikTitleKey(nca_header_t *dec_nca_header, u8 *out_tik, u8 *out_en
|
|||
if (!setcal_eticket_retrieved)
|
||||
{
|
||||
// Get extended eTicket RSA key from PRODINFO
|
||||
memset(eticket_data, 0, ETICKET_DEVKEY_DATA_SIZE);
|
||||
memset(&eticket_data, 0, sizeof(SetCalRsa2048DeviceKey));
|
||||
|
||||
result = setcalInitialize();
|
||||
if (R_FAILED(result))
|
||||
|
@ -954,7 +1003,7 @@ int retrieveNcaTikTitleKey(nca_header_t *dec_nca_header, u8 *out_tik, u8 *out_en
|
|||
return ret;
|
||||
}
|
||||
|
||||
result = setcalGetEticketDeviceKey(eticket_data);
|
||||
result = setcalGetEticketDeviceKey(&eticket_data);
|
||||
|
||||
setcalExit();
|
||||
|
||||
|
@ -965,22 +1014,22 @@ int retrieveNcaTikTitleKey(nca_header_t *dec_nca_header, u8 *out_tik, u8 *out_en
|
|||
}
|
||||
|
||||
// Decrypt eTicket RSA key
|
||||
memcpy(ctr, eticket_data + ETICKET_DEVKEY_CTR_OFFSET, 0x10);
|
||||
memcpy(ctr, eticket_data.key, ETICKET_DEVKEY_RSA_CTR_SIZE);
|
||||
aes128CtrContextCreate(&eticket_aes_ctx, nca_keyset.eticket_rsa_kek, ctr);
|
||||
aes128CtrCrypt(&eticket_aes_ctx, eticket_data + ETICKET_DEVKEY_RSA_OFFSET, eticket_data + ETICKET_DEVKEY_RSA_OFFSET, ETICKET_DEVKEY_RSA_SIZE);
|
||||
aes128CtrCrypt(&eticket_aes_ctx, eticket_data.key + ETICKET_DEVKEY_RSA_OFFSET, eticket_data.key + ETICKET_DEVKEY_RSA_OFFSET, ETICKET_DEVKEY_RSA_SIZE);
|
||||
|
||||
// Public exponent must use RSA-2048 SHA-1 signature method
|
||||
// The value is stored use big endian byte order
|
||||
if (bswap_32(*((u32*)(&(eticket_data[ETICKET_DEVKEY_RSA_OFFSET + 0x200])))) != SIGTYPE_RSA2048_SHA1)
|
||||
if (__builtin_bswap32(*((u32*)(eticket_data.key + ETICKET_DEVKEY_RSA_OFFSET + 0x200))) != SIGTYPE_RSA2048_SHA1)
|
||||
{
|
||||
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid public RSA exponent for eTicket data! Wrong keys?\nTry running Lockpick_RCM to generate the keys file from scratch.", __func__);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
D = &(eticket_data[ETICKET_DEVKEY_RSA_OFFSET]);
|
||||
N = &(eticket_data[ETICKET_DEVKEY_RSA_OFFSET + 0x100]);
|
||||
E = &(eticket_data[ETICKET_DEVKEY_RSA_OFFSET + 0x200]);
|
||||
D = (eticket_data.key + ETICKET_DEVKEY_RSA_OFFSET);
|
||||
N = (eticket_data.key + ETICKET_DEVKEY_RSA_OFFSET + 0x100);
|
||||
E = (eticket_data.key + ETICKET_DEVKEY_RSA_OFFSET + 0x200);
|
||||
|
||||
if (!setcal_eticket_retrieved)
|
||||
{
|
||||
|
@ -1006,7 +1055,6 @@ int retrieveNcaTikTitleKey(nca_header_t *dec_nca_header, u8 *out_tik, u8 *out_en
|
|||
|
||||
save_ctx->file = &eTicketSave;
|
||||
save_ctx->tool_ctx.action = 0;
|
||||
memcpy(save_ctx->save_mac_key, nca_keyset.save_mac_key, 0x10);
|
||||
|
||||
if (!save_process(save_ctx))
|
||||
{
|
||||
|
@ -1116,6 +1164,7 @@ int retrieveNcaTikTitleKey(nca_header_t *dec_nca_header, u8 *out_tik, u8 *out_en
|
|||
{
|
||||
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: unable to find a matching eTicket entry for NCA rights ID!", __func__);
|
||||
ret = -2;
|
||||
dumpSharedTikSavedata();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,10 +12,9 @@
|
|||
#define SEG_RODATA BIT(1)
|
||||
#define SEG_DATA BIT(2)
|
||||
|
||||
#define ETICKET_DEVKEY_DATA_SIZE 0x244
|
||||
#define ETICKET_DEVKEY_CTR_OFFSET 0x4
|
||||
#define ETICKET_DEVKEY_RSA_OFFSET 0x14
|
||||
#define ETICKET_DEVKEY_RSA_SIZE (ETICKET_DEVKEY_DATA_SIZE - ETICKET_DEVKEY_RSA_OFFSET)
|
||||
#define ETICKET_DEVKEY_RSA_CTR_SIZE 0x10
|
||||
#define ETICKET_DEVKEY_RSA_OFFSET ETICKET_DEVKEY_RSA_CTR_SIZE
|
||||
#define ETICKET_DEVKEY_RSA_SIZE 0x230
|
||||
|
||||
#define SIGTYPE_RSA2048_SHA1 (u32)0x10001
|
||||
#define SIGTYPE_RSA2048_SHA256 (u32)0x10004
|
||||
|
@ -25,13 +24,13 @@ typedef struct {
|
|||
u8 mask;
|
||||
u8 *data;
|
||||
u64 dataSize;
|
||||
} PACKED keyLocation;
|
||||
} keyLocation;
|
||||
|
||||
typedef struct {
|
||||
char name[128];
|
||||
u8 hash[SHA256_HASH_SIZE];
|
||||
u64 size;
|
||||
} PACKED keyInfo;
|
||||
} keyInfo;
|
||||
|
||||
typedef struct {
|
||||
u16 memory_key_cnt; /* Key counter for keys retrieved from memory. */
|
||||
|
@ -55,10 +54,7 @@ typedef struct {
|
|||
|
||||
// Needed to reencrypt the NCA key area for tik-less NSP dumps. Retrieved from the Lockpick_RCM keys file.
|
||||
u8 key_area_keys[0x20][3][0x10]; /* Key area encryption keys. */
|
||||
|
||||
// Console specific. Needed to calculate the AES CMAC for savefiles. Retrieved from the Lockpick_RCM keys file.
|
||||
u8 save_mac_key[0x10]; /* Savefile CMAC key */
|
||||
} PACKED nca_keyset_t;
|
||||
} nca_keyset_t;
|
||||
|
||||
bool loadMemoryKeys();
|
||||
bool decryptNcaKeyArea(nca_header_t *dec_nca_header, u8 *out);
|
||||
|
|
742
source/nca.c
742
source/nca.c
File diff suppressed because it is too large
Load diff
370
source/nca.h
370
source/nca.h
|
@ -194,7 +194,8 @@ typedef struct {
|
|||
};
|
||||
};
|
||||
u8 crypto_type2; /* Which keyblob (field 2) */
|
||||
u8 _0x221[0xF]; /* Padding. */
|
||||
u8 fixed_key_generation;
|
||||
u8 _0x222[0xE]; /* Padding. */
|
||||
u8 rights_id[0x10]; /* Rights ID (for titlekey crypto). */
|
||||
nca_section_entry_t section_entries[4]; /* Section entry metadata. */
|
||||
u8 section_hashes[4][0x20]; /* SHA-256 hashes for each section header. */
|
||||
|
@ -238,6 +239,7 @@ typedef struct {
|
|||
typedef struct {
|
||||
u64 patch_tid; /* Patch TID / Application TID */
|
||||
u32 min_sysver; /* Minimum system/application version */
|
||||
u32 min_appver; /* Minimum application version (only for base applications) */
|
||||
} PACKED cnmt_extended_header;
|
||||
|
||||
typedef struct {
|
||||
|
@ -259,7 +261,8 @@ typedef struct {
|
|||
u8 min_keyblob;
|
||||
u32 min_sysver;
|
||||
u64 patch_tid;
|
||||
} PACKED cnmt_xml_program_info;
|
||||
u32 min_appver;
|
||||
} cnmt_xml_program_info;
|
||||
|
||||
typedef struct {
|
||||
u8 type;
|
||||
|
@ -270,12 +273,13 @@ typedef struct {
|
|||
char hash_str[(SHA256_HASH_SIZE * 2) + 1];
|
||||
u8 keyblob;
|
||||
u8 id_offset;
|
||||
u64 cnt_record_offset; // Relative to the start of the content record structs in the CNMT
|
||||
u64 cnt_record_offset; // Relative to the start of the content records section in the CNMT
|
||||
u8 decrypted_nca_keys[NCA_KEY_AREA_SIZE];
|
||||
u8 encrypted_header_mod[NCA_FULL_HEADER_LENGTH];
|
||||
} PACKED cnmt_xml_content_info;
|
||||
} cnmt_xml_content_info;
|
||||
|
||||
typedef struct {
|
||||
u32 nca_index;
|
||||
u8 *hash_table;
|
||||
u64 hash_table_offset; // Relative to NCA start
|
||||
u64 hash_table_size;
|
||||
|
@ -283,7 +287,21 @@ typedef struct {
|
|||
u8 *block_data[2];
|
||||
u64 block_offset[2]; // Relative to NCA start
|
||||
u64 block_size[2];
|
||||
} PACKED nca_program_mod_data;
|
||||
} nca_program_mod_data;
|
||||
|
||||
typedef struct {
|
||||
char filename[100];
|
||||
u64 icon_size;
|
||||
u8 icon_data[0x20000];
|
||||
} nacp_icons_ctx;
|
||||
|
||||
typedef struct {
|
||||
u32 nca_index;
|
||||
u64 xml_size;
|
||||
char *xml_data;
|
||||
u8 nacp_icon_cnt; // Only used with Control NCAs
|
||||
nacp_icons_ctx *nacp_icons; // Only used with Control NCAs
|
||||
} xml_record_info;
|
||||
|
||||
typedef struct {
|
||||
u64 section_offset; // Relative to NCA start
|
||||
|
@ -295,7 +313,7 @@ typedef struct {
|
|||
u64 pfs0_size;
|
||||
u64 title_cnmt_offset; // Relative to NCA start
|
||||
u64 title_cnmt_size;
|
||||
} PACKED nca_cnmt_mod_data;
|
||||
} nca_cnmt_mod_data;
|
||||
|
||||
typedef struct {
|
||||
u32 sig_type;
|
||||
|
@ -327,12 +345,13 @@ typedef struct {
|
|||
rsa2048_sha256_ticket tik_data;
|
||||
bool retrieved_tik;
|
||||
bool missing_tik;
|
||||
} PACKED title_rights_ctx;
|
||||
} title_rights_ctx;
|
||||
|
||||
typedef struct {
|
||||
NcmStorageId storageId;
|
||||
NcmContentStorage ncmStorage;
|
||||
NcmContentId ncaId;
|
||||
u8 idOffset;
|
||||
Aes128CtrContext aes_ctx;
|
||||
u64 exefs_offset; // Relative to NCA start
|
||||
u64 exefs_size;
|
||||
|
@ -342,12 +361,13 @@ typedef struct {
|
|||
u64 exefs_str_table_offset; // Relative to NCA start
|
||||
char *exefs_str_table;
|
||||
u64 exefs_data_offset; // Relative to NCA start
|
||||
} PACKED exefs_ctx_t;
|
||||
} exefs_ctx_t;
|
||||
|
||||
typedef struct {
|
||||
NcmStorageId storageId;
|
||||
NcmContentStorage ncmStorage;
|
||||
NcmContentId ncaId;
|
||||
u8 idOffset;
|
||||
Aes128CtrContext aes_ctx;
|
||||
u64 section_offset; // Relative to NCA start
|
||||
u64 section_size;
|
||||
|
@ -360,7 +380,7 @@ typedef struct {
|
|||
u64 romfs_filetable_size;
|
||||
romfs_file *romfs_file_entries;
|
||||
u64 romfs_filedata_offset; // Relative to NCA start
|
||||
} PACKED romfs_ctx_t;
|
||||
} romfs_ctx_t;
|
||||
|
||||
typedef struct {
|
||||
u64 virt_offset;
|
||||
|
@ -409,6 +429,7 @@ typedef struct {
|
|||
NcmStorageId storageId;
|
||||
NcmContentStorage ncmStorage;
|
||||
NcmContentId ncaId;
|
||||
u8 idOffset;
|
||||
Aes128CtrContext aes_ctx;
|
||||
u64 section_offset; // Relative to NCA start
|
||||
u64 section_size;
|
||||
|
@ -427,94 +448,279 @@ typedef struct {
|
|||
u64 romfs_filetable_size;
|
||||
romfs_file *romfs_file_entries;
|
||||
u64 romfs_filedata_offset; // Relative to section start
|
||||
} PACKED bktr_ctx_t;
|
||||
} bktr_ctx_t;
|
||||
|
||||
// Used in HFS0 / ExeFS / RomFS browsers
|
||||
typedef struct {
|
||||
u64 size;
|
||||
char sizeStr[32];
|
||||
} PACKED browser_entry_size_info;
|
||||
} browser_entry_size_info;
|
||||
|
||||
typedef struct {
|
||||
u8 type; // 1 = Dir, 2 = File
|
||||
u64 offset; // Relative to directory/file table, depending on type
|
||||
browser_entry_size_info sizeInfo; // Only used if type == 2
|
||||
} PACKED romfs_browser_entry;
|
||||
} romfs_browser_entry;
|
||||
|
||||
typedef struct {
|
||||
u64 id;
|
||||
char name[0x200];
|
||||
char publisher[0x100];
|
||||
} Title;
|
||||
|
||||
typedef enum {
|
||||
Language_AmericanEnglish = 0,
|
||||
Language_BritishEnglish = 1,
|
||||
Language_Japanese = 2,
|
||||
Language_French = 3,
|
||||
Language_German = 4,
|
||||
Language_LatinAmericanSpanish = 5,
|
||||
Language_Spanish = 6,
|
||||
Language_Italian = 7,
|
||||
Language_Dutch = 8,
|
||||
Language_CanadianFrench = 9,
|
||||
Language_Portuguese = 10,
|
||||
Language_Russian = 11,
|
||||
Language_Korean = 12,
|
||||
Language_TraditionalChinese = 13,
|
||||
Language_SimplifiedChinese = 14
|
||||
} Language;
|
||||
|
||||
typedef enum {
|
||||
StartupUserAccount_None = 0,
|
||||
StartupUserAccount_Required = 1,
|
||||
StartupUserAccount_RequiredWithNetworkServiceAccountAvailable = 2
|
||||
} StartupUserAccount;
|
||||
|
||||
/* Introduced as of SDK 6.4.0 */
|
||||
typedef enum {
|
||||
UserAccountSwitchLock_Disable = 0,
|
||||
UserAccountSwitchLock_Enable = 1
|
||||
} UserAccountSwitchLock;
|
||||
|
||||
/* Introduced as of SDK 3.4.0 */
|
||||
typedef enum {
|
||||
AddOnContentRegistrationType_AllOnLaunch = 0,
|
||||
AddOnContentRegistrationType_OnDemand = 1
|
||||
} AddOnContentRegistrationType;
|
||||
|
||||
typedef struct {
|
||||
u32 AttributeFlag_Demo : 1;
|
||||
u32 AttributeFlag_RetailInteractiveDisplay : 1; /* Introduced as of SDK 3.4.0 */
|
||||
} AttributeFlag;
|
||||
|
||||
typedef struct {
|
||||
u32 SupportedLanguageFlag_AmericanEnglish : 1;
|
||||
u32 SupportedLanguageFlag_BritishEnglish : 1;
|
||||
u32 SupportedLanguageFlag_Japanese : 1;
|
||||
u32 SupportedLanguageFlag_French : 1;
|
||||
u32 SupportedLanguageFlag_German : 1;
|
||||
u32 SupportedLanguageFlag_LatinAmericanSpanish : 1;
|
||||
u32 SupportedLanguageFlag_Spanish : 1;
|
||||
u32 SupportedLanguageFlag_Italian : 1;
|
||||
u32 SupportedLanguageFlag_Dutch : 1;
|
||||
u32 SupportedLanguageFlag_CanadianFrench : 1;
|
||||
u32 SupportedLanguageFlag_Portuguese : 1;
|
||||
u32 SupportedLanguageFlag_Russian : 1;
|
||||
u32 SupportedLanguageFlag_Korean : 1;
|
||||
u32 SupportedLanguageFlag_TraditionalChinese : 1;
|
||||
u32 SupportedLanguageFlag_SimplifiedChinese : 1;
|
||||
} SupportedLanguageFlag;
|
||||
|
||||
typedef struct {
|
||||
u32 ParentalControlFlag_FreeCommunication : 1;
|
||||
} ParentalControlFlag;
|
||||
|
||||
typedef enum {
|
||||
Screenshot_Allow = 0,
|
||||
Screenshot_Deny = 1
|
||||
} Screenshot;
|
||||
|
||||
typedef enum {
|
||||
VideoCapture_Disable = 0,
|
||||
VideoCapture_Manual = 1,
|
||||
VideoCapture_Enable = 2
|
||||
} VideoCapture;
|
||||
|
||||
typedef enum {
|
||||
DataLossConfirmation_None = 0,
|
||||
DataLossConfirmation_Required = 1
|
||||
} DataLossConfirmation;
|
||||
|
||||
typedef enum {
|
||||
PlayLogPolicy_All = 0,
|
||||
PlayLogPolicy_LogOnly = 1,
|
||||
PlayLogPolicy_None = 2
|
||||
} PlayLogPolicy;
|
||||
|
||||
typedef enum {
|
||||
RatingAgeOrganization_CERO = 0,
|
||||
RatingAgeOrganization_GRACGCRB = 1,
|
||||
RatingAgeOrganization_GSRMR = 2,
|
||||
RatingAgeOrganization_ESRB = 3,
|
||||
RatingAgeOrganization_ClassInd = 4,
|
||||
RatingAgeOrganization_USK = 5,
|
||||
RatingAgeOrganization_PEGI = 6,
|
||||
RatingAgeOrganization_PEGIPortugal = 7,
|
||||
RatingAgeOrganization_PEGIBBFC = 8,
|
||||
RatingAgeOrganization_Russian = 9,
|
||||
RatingAgeOrganization_ACB = 10,
|
||||
RatingAgeOrganization_OFLC = 11,
|
||||
RatingAgeOrganization_IARCGeneric = 12 /* Introduced as of SDK 9.3.1 */
|
||||
} RatingAgeOrganization;
|
||||
|
||||
typedef struct {
|
||||
u8 cero;
|
||||
u8 gracgcrb;
|
||||
u8 gsrmr;
|
||||
u8 esrb;
|
||||
u8 class_ind;
|
||||
u8 usk;
|
||||
u8 pegi;
|
||||
u8 pegi_portugal;
|
||||
u8 pegibbfc;
|
||||
u8 russian;
|
||||
u8 acb;
|
||||
u8 oflc;
|
||||
u8 iarc_generic;
|
||||
u8 reserved_1[0x13];
|
||||
} RatingAge;
|
||||
|
||||
typedef enum {
|
||||
LogoType_LicensedByNintendo = 0,
|
||||
LogoType_DistributedByNintendo = 1, /* Removed in SDK 3.5.2 */
|
||||
LogoType_Nintendo = 2
|
||||
} LogoType;
|
||||
|
||||
typedef enum {
|
||||
LogoHandling_Auto = 0,
|
||||
LogoHandling_Manual = 1
|
||||
} LogoHandling;
|
||||
|
||||
/* Introduced as of SDK 4.5.0 */
|
||||
typedef enum {
|
||||
RuntimeAddOnContentInstall_Deny = 0,
|
||||
RuntimeAddOnContentInstall_AllowAppend = 1
|
||||
} RuntimeAddOnContentInstall;
|
||||
|
||||
/* Introduced as of SDK 9.3.1 */
|
||||
typedef enum {
|
||||
RuntimeParameterDelivery_Always = 0,
|
||||
RuntimeParameterDelivery_AlwaysIfUserStateMatched = 1,
|
||||
RuntimeParameterDelivery_OnRestart = 2
|
||||
} RuntimeParameterDelivery;
|
||||
|
||||
/* Introduced as of SDK 3.5.2 */
|
||||
typedef enum {
|
||||
CrashReport_Deny = 0,
|
||||
CrashReport_Allow = 1
|
||||
} CrashReport;
|
||||
|
||||
typedef enum {
|
||||
Hdcp_None = 0,
|
||||
Hdcp_Required = 1
|
||||
} Hdcp;
|
||||
|
||||
/* Introduced as of SDK 7.6.0 */
|
||||
typedef struct {
|
||||
u8 StartupUserAccountOptionFlag_IsOptional : 1;
|
||||
} StartupUserAccountOptionFlag;
|
||||
|
||||
/* Introduced as of SDK 5.3.0 */
|
||||
typedef enum {
|
||||
PlayLogQueryCapability_None = 0,
|
||||
PlayLogQueryCapability_WhiteList = 1,
|
||||
PlayLogQueryCapability_All = 2
|
||||
} PlayLogQueryCapability;
|
||||
|
||||
/* Introduced as of SDK 5.3.0 */
|
||||
typedef struct {
|
||||
u8 RepairFlag_SuppressGameCardAccess : 1;
|
||||
} RepairFlag;
|
||||
|
||||
/* Introduced as of SDK 6.4.0 */
|
||||
typedef struct {
|
||||
u8 RequiredNetworkServiceLicenseOnLaunchFlag_Common : 1;
|
||||
} RequiredNetworkServiceLicenseOnLaunchFlag;
|
||||
|
||||
typedef struct {
|
||||
u64 group_id;
|
||||
u8 key[0x10];
|
||||
} PACKED send_data_configuration;
|
||||
} NeighborDetectionGroupConfiguration;
|
||||
|
||||
typedef struct {
|
||||
u64 id;
|
||||
u8 key[0x10];
|
||||
} PACKED receivable_data_configurations;
|
||||
NeighborDetectionGroupConfiguration send_group_configuration;
|
||||
NeighborDetectionGroupConfiguration receivable_group_configurations[0x10];
|
||||
} NeighborDetectionClientConfiguration;
|
||||
|
||||
/* Introduced as of SDK 7.6.0 */
|
||||
typedef enum {
|
||||
JitConfigurationFlag_None = 0,
|
||||
JitConfigurationFlag_Enabled = 1
|
||||
} JitConfigurationFlag;
|
||||
|
||||
typedef struct {
|
||||
NacpLanguageEntry lang[16];
|
||||
char Isbn[0x25];
|
||||
u8 StartupUserAccount;
|
||||
u8 UserAccountSwitchLock;
|
||||
u8 AddOnContentRegistrationType;
|
||||
u32 AttributeFlag;
|
||||
u32 SupportedLanguageFlag;
|
||||
u32 ParentalControlFlag;
|
||||
u8 Screenshot;
|
||||
u8 VideoCapture;
|
||||
u8 DataLossConfirmation;
|
||||
u8 PlayLogPolicy;
|
||||
u64 PresenceGroupId;
|
||||
u8 RatingAge[0x20];
|
||||
char DisplayVersion[0x10];
|
||||
u64 AddOnContentBaseId;
|
||||
u64 SaveDataOwnerId;
|
||||
u64 UserAccountSaveDataSize;
|
||||
u64 UserAccountSaveDataJournalSize;
|
||||
u64 DeviceSaveDataSize;
|
||||
u64 DeviceSaveDataJournalSize;
|
||||
u64 BcatDeliveryCacheStorageSize;
|
||||
char ApplicationErrorCodeCategory[0x8];
|
||||
u64 LocalCommunicationId[0x8];
|
||||
u8 LogoType;
|
||||
u8 LogoHandling;
|
||||
u8 RuntimeAddOnContentInstall;
|
||||
u8 RuntimeParameterDelivery;
|
||||
u8 Reserved_0x30F4[0x2];
|
||||
u8 CrashReport;
|
||||
u8 Hdcp;
|
||||
u64 SeedForPseudoDeviceId;
|
||||
char BcatPassphrase[0x41];
|
||||
u8 StartupUserAccountOptionFlag;
|
||||
u8 ReservedForUserAccountSaveDataOperation[0x6];
|
||||
u64 UserAccountSaveDataSizeMax;
|
||||
u64 UserAccountSaveDataJournalSizeMax;
|
||||
u64 DeviceSaveDataSizeMax;
|
||||
u64 DeviceSaveDataJournalSizeMax;
|
||||
u64 TemporaryStorageSize;
|
||||
u64 CacheStorageSize;
|
||||
u64 CacheStorageJournalSize;
|
||||
u64 CacheStorageDataAndJournalSizeMax;
|
||||
u16 CacheStorageIndexMax;
|
||||
u8 Reserved_0x318A[0x6];
|
||||
u64 PlayLogQueryableApplicationId[0x10];
|
||||
u8 PlayLogQueryCapability;
|
||||
u8 RepairFlag;
|
||||
u8 ProgramIndex;
|
||||
u8 RequiredNetworkServiceLicenseOnLaunchFlag;
|
||||
u8 Reserved_0x3214[0x4];
|
||||
send_data_configuration SendDataConfiguration;
|
||||
receivable_data_configurations ReceivableDataConfiguration[0x10];
|
||||
u64 JitConfigurationFlag;
|
||||
u64 JitMemorySize;
|
||||
u8 Reserved[0xC40];
|
||||
} PACKED nacp_t;
|
||||
u64 jit_configuration_flag;
|
||||
u64 memory_size;
|
||||
} JitConfiguration;
|
||||
|
||||
typedef struct {
|
||||
char filename[100];
|
||||
u64 icon_size;
|
||||
u8 icon_data[0x20000];
|
||||
} PACKED nacp_icons_ctx;
|
||||
Title titles[0x10];
|
||||
char isbn[0x25];
|
||||
u8 startup_user_account;
|
||||
u8 user_account_switch_lock; /* Old: touch_screen_usage (None, Supported, Required) */
|
||||
u8 add_on_content_registration_type;
|
||||
AttributeFlag attribute_flag;
|
||||
SupportedLanguageFlag supported_language_flag;
|
||||
ParentalControlFlag parental_control_flag;
|
||||
u8 screenshot;
|
||||
u8 video_capture;
|
||||
u8 data_loss_confirmation;
|
||||
u8 play_log_policy;
|
||||
u64 presence_group_id;
|
||||
RatingAge rating_ages;
|
||||
char display_version[0x10];
|
||||
u64 add_on_content_base_id;
|
||||
u64 save_data_owner_id;
|
||||
u64 user_account_save_data_size;
|
||||
u64 user_account_save_data_journal_size;
|
||||
u64 device_save_data_size;
|
||||
u64 device_save_data_journal_size;
|
||||
u64 bcat_delivery_cache_storage_size;
|
||||
char application_error_code_category[0x8];
|
||||
u64 local_communication_ids[0x8];
|
||||
u8 logo_type;
|
||||
u8 logo_handling;
|
||||
u8 runtime_add_on_content_install;
|
||||
u8 runtime_parameter_delivery;
|
||||
u8 reserved_1[0x2];
|
||||
u8 crash_report;
|
||||
u8 hdcp;
|
||||
u64 seed_for_pseudo_device_id;
|
||||
char bcat_passphrase[0x41];
|
||||
StartupUserAccountOptionFlag startup_user_account_option;
|
||||
u8 reserved_2[0x6];
|
||||
u64 user_account_save_data_size_max;
|
||||
u64 user_account_save_data_journal_size_max;
|
||||
u64 device_save_data_size_max;
|
||||
u64 device_save_data_journal_size_max;
|
||||
u64 temporary_storage_size;
|
||||
u64 cache_storage_size;
|
||||
u64 cache_storage_journal_size;
|
||||
u64 cache_storage_data_and_journal_size_max;
|
||||
u16 cache_storage_index_max;
|
||||
u8 reserved_3[0x6];
|
||||
u64 play_log_queryable_application_ids[0x10];
|
||||
u8 play_log_query_capability;
|
||||
RepairFlag repair_flag;
|
||||
u8 program_index;
|
||||
RequiredNetworkServiceLicenseOnLaunchFlag required_network_service_license_on_launch_flag;
|
||||
u8 reserved_4[0x4];
|
||||
NeighborDetectionClientConfiguration neighbor_detection_client_configuration;
|
||||
JitConfiguration jit_configuration;
|
||||
u8 reserved_5[0xC40];
|
||||
} nacp_t;
|
||||
|
||||
char *getContentType(u8 type);
|
||||
|
||||
void generateCnmtXml(cnmt_xml_program_info *xml_program_info, cnmt_xml_content_info *xml_content_info, char *out);
|
||||
|
||||
|
@ -532,9 +738,11 @@ bool encryptNcaHeader(nca_header_t *input, u8 *outBuf, u64 outBufSize);
|
|||
|
||||
bool decryptNcaHeader(const u8 *ncaBuf, u64 ncaBufSize, nca_header_t *out, title_rights_ctx *rights_info, u8 *decrypted_nca_keys, bool retrieveTitleKeyData);
|
||||
|
||||
bool processProgramNca(NcmContentStorage *ncmStorage, const NcmContentId *ncaId, nca_header_t *dec_nca_header, cnmt_xml_content_info *xml_content_info, nca_program_mod_data *output);
|
||||
bool retrieveTitleKeyFromGameCardTicket(title_rights_ctx *rights_info, u8 *decrypted_nca_keys);
|
||||
|
||||
bool retrieveCnmtNcaData(NcmStorageId curStorageId, nspDumpType selectedNspDumpType, u8 *ncaBuf, cnmt_xml_program_info *xml_program_info, cnmt_xml_content_info *xml_content_info, u32 cnmtNcaIndex, nca_cnmt_mod_data *output, title_rights_ctx *rights_info);
|
||||
bool processProgramNca(NcmContentStorage *ncmStorage, const NcmContentId *ncaId, nca_header_t *dec_nca_header, cnmt_xml_content_info *xml_content_info, nca_program_mod_data **output, u32 *cur_mod_cnt, u32 idx);
|
||||
|
||||
bool retrieveCnmtNcaData(NcmStorageId curStorageId, u8 *ncaBuf, cnmt_xml_program_info *xml_program_info, cnmt_xml_content_info *xml_content_info, u32 cnmtNcaIndex, nca_cnmt_mod_data *output, title_rights_ctx *rights_info);
|
||||
|
||||
bool patchCnmtNca(u8 *ncaBuf, u64 ncaBufSize, cnmt_xml_program_info *xml_program_info, cnmt_xml_content_info *xml_content_info, nca_cnmt_mod_data *cnmt_mod);
|
||||
|
||||
|
@ -544,7 +752,7 @@ bool parseRomFsEntryFromNca(NcmContentStorage *ncmStorage, const NcmContentId *n
|
|||
|
||||
bool parseBktrEntryFromNca(NcmContentStorage *ncmStorage, const NcmContentId *ncaId, nca_header_t *dec_nca_header, u8 *decrypted_nca_keys);
|
||||
|
||||
bool generateProgramInfoXml(NcmContentStorage *ncmStorage, const NcmContentId *ncaId, nca_header_t *dec_nca_header, u8 *decrypted_nca_keys, nca_program_mod_data *program_mod_data, char **outBuf, u64 *outBufSize);
|
||||
bool generateProgramInfoXml(NcmContentStorage *ncmStorage, const NcmContentId *ncaId, nca_header_t *dec_nca_header, u8 *decrypted_nca_keys, bool useCustomAcidRsaPubKey, char **outBuf, u64 *outBufSize);
|
||||
|
||||
bool retrieveNacpDataFromNca(NcmContentStorage *ncmStorage, const NcmContentId *ncaId, nca_header_t *dec_nca_header, u8 *decrypted_nca_keys, char **out_nacp_xml, u64 *out_nacp_xml_size, nacp_icons_ctx **out_nacp_icons_ctx, u8 *out_nacp_icons_ctx_cnt);
|
||||
|
||||
|
|
|
@ -331,9 +331,9 @@ bool retrieveSymbolsListFromNso(NcmContentStorage *ncmStorage, const NcmContentI
|
|||
mod_magic = *((u32*)(&(nsoBinaryData[mod_magic_offset])));
|
||||
dynamic_section_offset = ((s32)mod_magic_offset + *((s32*)(&(nsoBinaryData[mod_magic_offset + 0x04]))));
|
||||
|
||||
if (bswap_32(mod_magic) != MOD_MAGIC)
|
||||
if (__builtin_bswap32(mod_magic) != MOD_MAGIC)
|
||||
{
|
||||
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid MOD0 magic word in decompressed NSO from Program NCA! (0x%08X)", __func__, bswap_32(mod_magic));
|
||||
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid MOD0 magic word in decompressed NSO from Program NCA! (0x%08X)", __func__, __builtin_bswap32(mod_magic));
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
|
@ -1881,7 +1881,6 @@ bool readCertsFromSystemSave()
|
|||
|
||||
save_ctx->file = &certSave;
|
||||
save_ctx->tool_ctx.action = 0;
|
||||
memcpy(save_ctx->save_mac_key, nca_keyset.save_mac_key, 0x10);
|
||||
|
||||
initSaveCtx = save_process(save_ctx);
|
||||
if (!initSaveCtx)
|
||||
|
|
|
@ -84,11 +84,13 @@ typedef struct {
|
|||
u8 _0x190[0x70];
|
||||
} fs_layout_t;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
u64 offset;
|
||||
u64 length;
|
||||
u32 block_size_power;
|
||||
} PACKED duplex_info_t;
|
||||
} duplex_info_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
typedef struct {
|
||||
u32 magic; /* DPFS */
|
||||
|
@ -142,6 +144,7 @@ typedef struct {
|
|||
typedef struct remap_segment_ctx_t remap_segment_ctx_t;
|
||||
typedef struct remap_entry_ctx_t remap_entry_ctx_t;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct remap_entry_ctx_t {
|
||||
u64 virtual_offset;
|
||||
u64 physical_offset;
|
||||
|
@ -152,7 +155,8 @@ struct remap_entry_ctx_t {
|
|||
u64 physical_offset_end;
|
||||
remap_segment_ctx_t *segment;
|
||||
remap_entry_ctx_t *next;
|
||||
} PACKED;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
struct remap_segment_ctx_t{
|
||||
u64 offset;
|
||||
|
@ -215,6 +219,7 @@ typedef struct {
|
|||
u8 salt_source[0x20];
|
||||
} ivfc_save_hdr_t;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
u8 cmac[0x10];
|
||||
u8 _0x10[0xF0];
|
||||
|
@ -233,7 +238,8 @@ typedef struct {
|
|||
u8 _0x748[0x390];
|
||||
ivfc_save_hdr_t fat_ivfc_header;
|
||||
u8 _0xB98[0x3468];
|
||||
} PACKED save_header_t;
|
||||
} save_header_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
typedef struct {
|
||||
duplex_storage_ctx_t layers[2];
|
||||
|
@ -344,32 +350,40 @@ typedef struct {
|
|||
u32 parent;
|
||||
} save_entry_key_t;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
u32 start_block;
|
||||
u64 length;
|
||||
u32 _0xC[2];
|
||||
} PACKED save_file_info_t;
|
||||
} save_file_info_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
u32 next_directory;
|
||||
u32 next_file;
|
||||
u32 _0x8[3];
|
||||
} PACKED save_find_position_t;
|
||||
} save_find_position_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
u32 next_sibling;
|
||||
union { /* Save table entry type. Size = 0x14. */
|
||||
save_file_info_t save_file_info;
|
||||
save_find_position_t save_find_position;
|
||||
};
|
||||
} PACKED save_table_entry_t;
|
||||
} save_table_entry_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
u32 parent;
|
||||
char name[SAVE_FS_LIST_MAX_NAME_LENGTH];
|
||||
save_table_entry_t value;
|
||||
u32 next;
|
||||
} PACKED save_fs_list_entry_t;
|
||||
} save_fs_list_entry_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
typedef struct {
|
||||
u32 free_list_head_index;
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
#include <switch/arm/atomics.h>
|
||||
#include <switch/services/sm.h>
|
||||
#include <switch/types.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "set_ext.h"
|
||||
#include "service_guard.h"
|
||||
|
||||
static Service g_setcalSrv;
|
||||
|
||||
NX_GENERATE_SERVICE_GUARD(setcal);
|
||||
|
||||
Result _setcalInitialize() {
|
||||
return smGetService(&g_setcalSrv, "set:cal");
|
||||
}
|
||||
|
||||
void _setcalCleanup() {
|
||||
serviceClose(&g_setcalSrv);
|
||||
}
|
||||
|
||||
Result setcalGetEticketDeviceKey(void *key)
|
||||
{
|
||||
return serviceDispatch(&g_setcalSrv, 21,
|
||||
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
|
||||
.buffers = { { key, 0x244 } },
|
||||
);
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#ifndef __SET_EXT_H__
|
||||
#define __SET_EXT_H__
|
||||
|
||||
#include <switch.h>
|
||||
|
||||
Result setcalInitialize(void);
|
||||
void setcalExit(void);
|
||||
|
||||
/**
|
||||
* @brief Gets the extended ETicket RSA-2048 Key from CAL0
|
||||
* @param key Pointer to 0x244-byte output buffer.
|
||||
*/
|
||||
Result setcalGetEticketDeviceKey(void *key);
|
||||
|
||||
#endif
|
295
source/ui.c
295
source/ui.c
|
@ -25,8 +25,6 @@ extern dumpOptions dumpCfg;
|
|||
|
||||
extern bool keysFileAvailable;
|
||||
|
||||
extern AppletType programAppletType;
|
||||
|
||||
extern gamecard_ctx_t gameCardInfo;
|
||||
|
||||
extern u32 titleAppCount, titlePatchCount, titleAddOnCount;
|
||||
|
@ -36,8 +34,8 @@ extern u32 emmcTitleAppCount, emmcTitlePatchCount, emmcTitleAddOnCount;
|
|||
extern base_app_ctx_t *baseAppEntries;
|
||||
extern patch_addon_ctx_t *patchEntries, *addOnEntries;
|
||||
|
||||
extern char *filenames[FILENAME_MAX_CNT];
|
||||
extern int filenamesCount;
|
||||
extern char **filenameBuffer;
|
||||
extern int filenameCount;
|
||||
|
||||
extern char curRomFsPath[NAME_BUF_LEN];
|
||||
extern romfs_browser_entry *romFsBrowserEntries;
|
||||
|
@ -114,10 +112,10 @@ static const char *dirHighlightIconPath = "romfs:/browser/dir_highlight.jpg";
|
|||
static u8 *dirHighlightIconBuf = NULL;
|
||||
|
||||
static const char *fileNormalIconPath = "romfs:/browser/file_normal.jpg";
|
||||
static u8 *fileNormalIconBuf = NULL;
|
||||
u8 *fileNormalIconBuf = NULL;
|
||||
|
||||
static const char *fileHighlightIconPath = "romfs:/browser/file_highlight.jpg";
|
||||
static u8 *fileHighlightIconBuf = NULL;
|
||||
u8 *fileHighlightIconBuf = NULL;
|
||||
|
||||
static const char *enabledNormalIconPath = "romfs:/browser/enabled_normal.jpg";
|
||||
u8 *enabledNormalIconBuf = NULL;
|
||||
|
@ -197,15 +195,15 @@ void uiFill(int x, int y, int width, int height, u8 r, u8 g, u8 b)
|
|||
framebuf_width = (stride / sizeof(u32));
|
||||
}
|
||||
|
||||
u32 lx, ly;
|
||||
int lx, ly;
|
||||
u32 framex, framey;
|
||||
|
||||
for (ly = 0; ly < height; ly++)
|
||||
{
|
||||
for (lx = 0; lx < width; lx++)
|
||||
{
|
||||
framex = (x + lx);
|
||||
framey = (y + ly);
|
||||
framex = (u32)(x + lx);
|
||||
framey = (u32)(y + ly);
|
||||
|
||||
framebuf[(framey * framebuf_width) + framex] = RGBA8_MAXALPHA(r, g, b);
|
||||
}
|
||||
|
@ -241,18 +239,17 @@ void uiDrawIcon(const u8 *icon, int width, int height, int x, int y)
|
|||
framebuf_width = (stride / sizeof(u32));
|
||||
}
|
||||
|
||||
u32 lx, ly;
|
||||
u32 framex, framey;
|
||||
u32 pos = 0;
|
||||
int lx, ly;
|
||||
u32 framex, framey, pos;
|
||||
|
||||
for (ly = 0; ly < height; ly++)
|
||||
{
|
||||
for (lx = 0; lx < width; lx++)
|
||||
{
|
||||
framex = (x + lx);
|
||||
framey = (y + ly);
|
||||
framex = (u32)(x + lx);
|
||||
framey = (u32)(y + ly);
|
||||
|
||||
pos = (((ly * width) + lx) * 3);
|
||||
pos = (u32)(((ly * width) + lx) * 3);
|
||||
|
||||
framebuf[(framey * framebuf_width) + framex] = RGBA8_MAXALPHA(icon[pos], icon[pos + 1], icon[pos + 2]);
|
||||
}
|
||||
|
@ -458,8 +455,8 @@ void uiDrawString(int x, int y, u8 r, u8 g, u8 b, const char *fmt, ...)
|
|||
vsnprintf(string, MAX_CHARACTERS(string), fmt, args);
|
||||
va_end(args);
|
||||
|
||||
u32 tmpx = (x <= 8 ? 8 : (x + 8));
|
||||
u32 tmpy = (font_height + (y <= 8 ? 8 : (y + 8)));
|
||||
u32 tmpx = (x < 8 ? 8 : x);
|
||||
u32 tmpy = (font_height + (y < 8 ? 8 : y));
|
||||
|
||||
FT_Error ret = 0;
|
||||
FT_UInt glyph_index = 0;
|
||||
|
@ -513,7 +510,7 @@ void uiDrawString(int x, int y, u8 r, u8 g, u8 b, const char *fmt, ...)
|
|||
|
||||
if (ret) break;
|
||||
|
||||
if ((tmpx + (sharedFontsFaces[j]->glyph->advance.x >> 6)) >= (FB_WIDTH - 8))
|
||||
if ((tmpx + (sharedFontsFaces[j]->glyph->advance.x >> 6)) > (FB_WIDTH - 8))
|
||||
{
|
||||
tmpx = 8;
|
||||
tmpy += LINE_HEIGHT;
|
||||
|
@ -555,7 +552,7 @@ u32 uiGetStrWidth(const char *fmt, ...)
|
|||
|
||||
if (tmpchar == '\n' || tmpchar == '\r')
|
||||
{
|
||||
continue;
|
||||
break;
|
||||
} else
|
||||
if (tmpchar == '\t')
|
||||
{
|
||||
|
@ -606,12 +603,12 @@ void uiUpdateStatusMsg()
|
|||
{
|
||||
if (!strlen(statusMessage) || !statusMessageFadeout) return;
|
||||
|
||||
uiFill(0, FB_HEIGHT - (font_height + STRING_Y_POS(1)), FB_WIDTH, font_height + STRING_Y_POS(1), BG_COLOR_RGB);
|
||||
uiFill(0, FB_HEIGHT - (font_height * 2), FB_WIDTH, font_height * 2, BG_COLOR_RGB);
|
||||
|
||||
if ((statusMessageFadeout - 4) > bgColors[0])
|
||||
{
|
||||
int fadeout = (statusMessageFadeout > 255 ? 255 : statusMessageFadeout);
|
||||
uiDrawString(STRING_X_POS, FB_HEIGHT - (font_height + STRING_Y_POS(1)), fadeout, fadeout, fadeout, statusMessage);
|
||||
uiDrawString(STRING_X_POS, FB_HEIGHT - (font_height * 2), fadeout, fadeout, fadeout, statusMessage);
|
||||
statusMessageFadeout -= 4;
|
||||
} else {
|
||||
statusMessageFadeout = 0;
|
||||
|
@ -645,7 +642,7 @@ void uiPrintHeadline()
|
|||
|
||||
void uiPrintOption(int x, int y, int endPosition, bool leftArrow, bool rightArrow, int r, int g, int b, const char *fmt, ...)
|
||||
{
|
||||
if (x < 8 || x >= OPTIONS_X_END_POS || y < 8 || y >= (FB_HEIGHT - 8 - font_height) || endPosition < OPTIONS_X_END_POS || endPosition >= (FB_WIDTH - 8) || !fmt || !*fmt) return;
|
||||
if (x < 8 || x > OPTIONS_X_END_POS || y < 8 || y > (FB_HEIGHT - 8) || endPosition < OPTIONS_X_END_POS || endPosition > (FB_WIDTH - 8) || !fmt || !*fmt) return;
|
||||
|
||||
int xpos = x;
|
||||
char option[NAME_BUF_LEN] = {'\0'};
|
||||
|
@ -675,16 +672,18 @@ void uiPrintOption(int x, int y, int endPosition, bool leftArrow, bool rightArro
|
|||
|
||||
void uiTruncateOptionStr(char *str, int x, int y, int endPosition)
|
||||
{
|
||||
if (!str || !strlen(str) || x < 8 || x >= OPTIONS_X_END_POS || y < 8 || y >= (FB_HEIGHT - 8 - font_height) || endPosition < OPTIONS_X_END_POS || endPosition >= (FB_WIDTH - 8)) return;
|
||||
if (!str || !strlen(str) || x < 8 || x > OPTIONS_X_END_POS || y < 8 || y > (FB_HEIGHT - 8) || endPosition < OPTIONS_X_END_POS || endPosition > (FB_WIDTH - 8)) return;
|
||||
|
||||
int xpos = x;
|
||||
char *option = str;
|
||||
|
||||
u32 optionStrWidth = uiGetStrWidth(option);
|
||||
u32 limit = (u32)(endPosition - xpos - (font_height * 2));
|
||||
|
||||
// Check if we're dealing with a long title selector string
|
||||
if (optionStrWidth >= (endPosition - xpos - (font_height * 2)))
|
||||
if (optionStrWidth >= limit)
|
||||
{
|
||||
while(optionStrWidth >= (endPosition - xpos - (font_height * 2)))
|
||||
while(optionStrWidth >= limit)
|
||||
{
|
||||
option++;
|
||||
optionStrWidth = uiGetStrWidth(option);
|
||||
|
@ -1075,15 +1074,6 @@ UIResult uiProcess()
|
|||
if (titleAppCount)
|
||||
{
|
||||
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "Error: unable to retrieve title entries from the inserted gamecard!");
|
||||
|
||||
if (strlen(gameCardInfo.updateVersionStr))
|
||||
{
|
||||
breaks++;
|
||||
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_SUCCESS_RGB, "Bundled FW Update: %s", gameCardInfo.updateVersionStr);
|
||||
breaks++;
|
||||
|
||||
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_RGB, "In order to be able to dump data from this gamecard, make sure your console is at least on this FW version.");
|
||||
}
|
||||
} else {
|
||||
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "Error: gamecard application count is zero!");
|
||||
}
|
||||
|
@ -1103,6 +1093,14 @@ UIResult uiProcess()
|
|||
{
|
||||
if (forcedXciDump)
|
||||
{
|
||||
if (strlen(gameCardInfo.updateVersionStr))
|
||||
{
|
||||
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_SUCCESS_RGB, "Bundled FW Update: %s", gameCardInfo.updateVersionStr);
|
||||
breaks++;
|
||||
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_RGB, "In order to be able to parse any kind of metadata from this gamecard and/or dump its contents to NSPs,\nmake sure your console is at least on this FW version.");
|
||||
breaks += 2;
|
||||
}
|
||||
|
||||
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_RGB, "Press " NINTENDO_FONT_Y " to dump the gamecard to \"gamecard.xci\".");
|
||||
} else {
|
||||
if (!gameCardInfo.rootHfs0Header) uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_RGB, "Are you using \"nogc\" spoofing in your CFW? If so, please consider this option disables all gamecard I/O.");
|
||||
|
@ -1115,7 +1113,7 @@ UIResult uiProcess()
|
|||
res = resultShowGameCardMenu;
|
||||
|
||||
hidScanInput();
|
||||
keysDown = hidKeysDown(CONTROLLER_P1_AUTO);
|
||||
keysDown = hidKeysAllDown(CONTROLLER_P1_AUTO);
|
||||
|
||||
// Exit
|
||||
if (keysDown & KEY_PLUS) res = resultExit;
|
||||
|
@ -1174,7 +1172,7 @@ UIResult uiProcess()
|
|||
res = resultShowSdCardEmmcMenu;
|
||||
|
||||
hidScanInput();
|
||||
keysDown = hidKeysDown(CONTROLLER_P1_AUTO);
|
||||
keysDown = hidKeysAllDown(CONTROLLER_P1_AUTO);
|
||||
|
||||
// Exit
|
||||
if (keysDown & KEY_PLUS) res = resultExit;
|
||||
|
@ -1209,7 +1207,7 @@ UIResult uiProcess()
|
|||
/* Draw icon */
|
||||
if (baseAppEntries[selectedAppInfoIndex].icon != NULL)
|
||||
{
|
||||
uiDrawIcon(baseAppEntries[selectedAppInfoIndex].icon, NACP_ICON_DOWNSCALED, NACP_ICON_DOWNSCALED, xpos, ypos + 8);
|
||||
uiDrawIcon(baseAppEntries[selectedAppInfoIndex].icon, NACP_ICON_DOWNSCALED, NACP_ICON_DOWNSCALED, xpos, ypos);
|
||||
xpos += (NACP_ICON_DOWNSCALED + 8);
|
||||
ypos += 8;
|
||||
}
|
||||
|
@ -1643,8 +1641,8 @@ UIResult uiProcess()
|
|||
|
||||
break;
|
||||
case stateHfs0Browser:
|
||||
menu = (const char**)filenames;
|
||||
menuItemsCount = filenamesCount;
|
||||
menu = (const char**)filenameBuffer;
|
||||
menuItemsCount = filenameCount;
|
||||
|
||||
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_TITLE_RGB, (gameCardInfo.hfs0PartitionCnt == GAMECARD_TYPE1_PARTITION_CNT ? hfs0BrowserType1MenuItems[selectedPartitionIndex] : hfs0BrowserType2MenuItems[selectedPartitionIndex]));
|
||||
breaks += 2;
|
||||
|
@ -1674,8 +1672,8 @@ UIResult uiProcess()
|
|||
|
||||
break;
|
||||
case stateExeFsSectionBrowser:
|
||||
menu = (const char**)filenames;
|
||||
menuItemsCount = filenamesCount;
|
||||
menu = (const char**)filenameBuffer;
|
||||
menuItemsCount = filenameCount;
|
||||
|
||||
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_TITLE_RGB, exeFsMenuItems[1]);
|
||||
breaks++;
|
||||
|
@ -1718,8 +1716,8 @@ UIResult uiProcess()
|
|||
|
||||
break;
|
||||
case stateRomFsSectionBrowser:
|
||||
menu = (const char**)filenames;
|
||||
menuItemsCount = filenamesCount;
|
||||
menu = (const char**)filenameBuffer;
|
||||
menuItemsCount = filenameCount;
|
||||
|
||||
// Skip the parent directory entry ("..") in the RomFS browser if we're currently at the root directory
|
||||
if (menu && menuItemsCount && strlen(curRomFsPath) <= 1)
|
||||
|
@ -1757,9 +1755,9 @@ UIResult uiProcess()
|
|||
|
||||
if (strlen(curRomFsPath) <= 1 || (strlen(curRomFsPath) > 1 && cursor > 0))
|
||||
{
|
||||
snprintf(strbuf, MAX_CHARACTERS(strbuf), "Entry count: %d | Current entry: %d", filenamesCount - 1, (strlen(curRomFsPath) <= 1 ? (cursor + 1) : cursor));
|
||||
snprintf(strbuf, MAX_CHARACTERS(strbuf), "Entry count: %d | Current entry: %d", filenameCount - 1, (strlen(curRomFsPath) <= 1 ? (cursor + 1) : cursor));
|
||||
} else {
|
||||
snprintf(strbuf, MAX_CHARACTERS(strbuf), "Entry count: %d", filenamesCount - 1);
|
||||
snprintf(strbuf, MAX_CHARACTERS(strbuf), "Entry count: %d", filenameCount - 1);
|
||||
}
|
||||
|
||||
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_RGB, strbuf);
|
||||
|
@ -1768,8 +1766,8 @@ UIResult uiProcess()
|
|||
case stateSdCardEmmcMenu:
|
||||
generateSdCardEmmcTitleList();
|
||||
|
||||
menu = (const char**)filenames;
|
||||
menuItemsCount = filenamesCount;
|
||||
menu = (const char**)filenameBuffer;
|
||||
menuItemsCount = filenameCount;
|
||||
|
||||
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_TITLE_RGB, mainMenuItems[1]);
|
||||
|
||||
|
@ -1795,8 +1793,8 @@ UIResult uiProcess()
|
|||
// Otherwise, this will only fill filenameBuffer
|
||||
generateOrphanPatchOrAddOnList();
|
||||
|
||||
menu = (const char**)filenames;
|
||||
menuItemsCount = filenamesCount;
|
||||
menu = (const char**)filenameBuffer;
|
||||
menuItemsCount = filenameCount;
|
||||
|
||||
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_TITLE_RGB, "Dump installed content with missing base application");
|
||||
|
||||
|
@ -1836,12 +1834,7 @@ UIResult uiProcess()
|
|||
{
|
||||
breaks++;
|
||||
|
||||
if (scroll > 0)
|
||||
{
|
||||
u32 arrowWidth = uiGetStrWidth(upwardsArrow);
|
||||
|
||||
uiDrawString((FB_WIDTH / 2) - (arrowWidth / 2), STRING_Y_POS(breaks), FONT_COLOR_RGB, upwardsArrow);
|
||||
}
|
||||
if (scroll > 0) uiDrawString((FB_WIDTH / 2) - (uiGetStrWidth(upwardsArrow) / 2), STRING_Y_POS(breaks), FONT_COLOR_RGB, upwardsArrow);
|
||||
|
||||
breaks++;
|
||||
|
||||
|
@ -1971,19 +1964,19 @@ UIResult uiProcess()
|
|||
}
|
||||
|
||||
xpos = STRING_X_POS;
|
||||
ypos = ((breaks * LINE_HEIGHT) + (uiState == stateSdCardEmmcMenu ? (j * (NACP_ICON_DOWNSCALED + 12)) : (j * (font_height + 12))) + 6);
|
||||
ypos = (8 + (breaks * LINE_HEIGHT) + (uiState == stateSdCardEmmcMenu ? (j * (NACP_ICON_DOWNSCALED + 12)) : (j * (font_height + 12))) + 6);
|
||||
|
||||
if (i == cursor)
|
||||
{
|
||||
highlight = true;
|
||||
uiFill(0, (ypos + 8) - 6, FB_WIDTH, (uiState == stateSdCardEmmcMenu ? (NACP_ICON_DOWNSCALED + 12) : (font_height + 12)), HIGHLIGHT_BG_COLOR_RGB);
|
||||
uiFill(0, ypos - 6, FB_WIDTH, (uiState == stateSdCardEmmcMenu ? (NACP_ICON_DOWNSCALED + 12) : (font_height + 12)), HIGHLIGHT_BG_COLOR_RGB);
|
||||
}
|
||||
|
||||
if (uiState == stateSdCardEmmcMenu)
|
||||
{
|
||||
if (baseAppEntries[i].icon != NULL)
|
||||
{
|
||||
uiDrawIcon(baseAppEntries[i].icon, NACP_ICON_DOWNSCALED, NACP_ICON_DOWNSCALED, xpos, ypos + 8);
|
||||
uiDrawIcon(baseAppEntries[i].icon, NACP_ICON_DOWNSCALED, NACP_ICON_DOWNSCALED, xpos, ypos);
|
||||
|
||||
xpos += (NACP_ICON_DOWNSCALED + 8);
|
||||
}
|
||||
|
@ -2002,7 +1995,7 @@ UIResult uiProcess()
|
|||
icon = (highlight ? fileHighlightIconBuf : fileNormalIconBuf);
|
||||
}
|
||||
|
||||
uiDrawIcon(icon, BROWSER_ICON_DIMENSION, BROWSER_ICON_DIMENSION, xpos, ypos + 8);
|
||||
uiDrawIcon(icon, BROWSER_ICON_DIMENSION, BROWSER_ICON_DIMENSION, xpos, ypos);
|
||||
|
||||
xpos += (BROWSER_ICON_DIMENSION + 8);
|
||||
}
|
||||
|
@ -2013,26 +2006,20 @@ UIResult uiProcess()
|
|||
|
||||
u32 idx = ((uiState == stateRomFsSectionBrowser && strlen(curRomFsPath) <= 1) ? (i + 1) : i); // Adjust index if we're at the root directory
|
||||
|
||||
if (uiState == stateHfs0Browser || uiState == stateExeFsSectionBrowser)
|
||||
if (uiState == stateHfs0Browser || uiState == stateExeFsSectionBrowser || (uiState == stateRomFsSectionBrowser && romFsBrowserEntries[idx].type == ROMFS_ENTRY_FILE))
|
||||
{
|
||||
uiDrawString(FB_WIDTH - (font_height * 7), ypos, HIGHLIGHT_FONT_COLOR_RGB, "(%s)", hfs0ExeFsEntriesSizes[idx].sizeStr);
|
||||
} else
|
||||
if (uiState == stateRomFsSectionBrowser && romFsBrowserEntries[idx].type == ROMFS_ENTRY_FILE)
|
||||
{
|
||||
uiDrawString(FB_WIDTH - (font_height * 7), ypos, HIGHLIGHT_FONT_COLOR_RGB, "(%s)", romFsBrowserEntries[idx].sizeInfo.sizeStr);
|
||||
snprintf(strbuf, MAX_CHARACTERS(strbuf), "(%s)", ((uiState == stateHfs0Browser || uiState == stateExeFsSectionBrowser) ? hfs0ExeFsEntriesSizes[idx].sizeStr : romFsBrowserEntries[idx].sizeInfo.sizeStr));
|
||||
uiDrawString(FB_WIDTH - (8 + uiGetStrWidth(strbuf)), ypos, HIGHLIGHT_FONT_COLOR_RGB, strbuf);
|
||||
}
|
||||
} else {
|
||||
uiDrawString(xpos, ypos, FONT_COLOR_RGB, menu[i]);
|
||||
|
||||
u32 idx = ((uiState == stateRomFsSectionBrowser && strlen(curRomFsPath) <= 1) ? (i + 1) : i); // Adjust index if we're at the root directory
|
||||
|
||||
if (uiState == stateHfs0Browser || uiState == stateExeFsSectionBrowser)
|
||||
if (uiState == stateHfs0Browser || uiState == stateExeFsSectionBrowser || (uiState == stateRomFsSectionBrowser && romFsBrowserEntries[idx].type == ROMFS_ENTRY_FILE))
|
||||
{
|
||||
uiDrawString(FB_WIDTH - (font_height * 7), ypos, FONT_COLOR_RGB, "(%s)", hfs0ExeFsEntriesSizes[idx].sizeStr);
|
||||
} else
|
||||
if (uiState == stateRomFsSectionBrowser && romFsBrowserEntries[idx].type == ROMFS_ENTRY_FILE)
|
||||
{
|
||||
uiDrawString(FB_WIDTH - (font_height * 7), ypos, FONT_COLOR_RGB, "(%s)", romFsBrowserEntries[idx].sizeInfo.sizeStr);
|
||||
snprintf(strbuf, MAX_CHARACTERS(strbuf), "(%s)", ((uiState == stateHfs0Browser || uiState == stateExeFsSectionBrowser) ? hfs0ExeFsEntriesSizes[idx].sizeStr : romFsBrowserEntries[idx].sizeInfo.sizeStr));
|
||||
uiDrawString(FB_WIDTH - (8 + uiGetStrWidth(strbuf)), ypos, FONT_COLOR_RGB, strbuf);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2197,9 +2184,9 @@ UIResult uiProcess()
|
|||
} else {
|
||||
if (highlight)
|
||||
{
|
||||
uiFill(FB_WIDTH / 2, (ypos + 8) - 6, FB_WIDTH / 2, font_height + 12, HIGHLIGHT_BG_COLOR_RGB);
|
||||
uiFill(FB_WIDTH / 2, ypos - 6, FB_WIDTH / 2, font_height + 12, HIGHLIGHT_BG_COLOR_RGB);
|
||||
} else {
|
||||
uiFill(FB_WIDTH / 2, (ypos + 8) - 6, FB_WIDTH / 2, font_height + 12, BG_COLOR_RGB);
|
||||
uiFill(FB_WIDTH / 2, ypos - 6, FB_WIDTH / 2, font_height + 12, BG_COLOR_RGB);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2534,51 +2521,43 @@ UIResult uiProcess()
|
|||
|
||||
if ((scroll + maxElements) < menuItemsCount)
|
||||
{
|
||||
ypos = ((breaks * LINE_HEIGHT) + (uiState == stateSdCardEmmcMenu ? (j * (NACP_ICON_DOWNSCALED + 12)) : (j * (font_height + 12))));
|
||||
|
||||
u32 arrowWidth = uiGetStrWidth(downwardsArrow);
|
||||
|
||||
uiDrawString((FB_WIDTH / 2) - (arrowWidth / 2), ypos, FONT_COLOR_RGB, downwardsArrow);
|
||||
ypos = (8 + (breaks * LINE_HEIGHT) + (uiState == stateSdCardEmmcMenu ? (j * (NACP_ICON_DOWNSCALED + 12)) : (j * (font_height + 12))));
|
||||
uiDrawString((FB_WIDTH / 2) - (uiGetStrWidth(downwardsArrow) / 2), ypos, FONT_COLOR_RGB, downwardsArrow);
|
||||
}
|
||||
|
||||
j++;
|
||||
if ((scroll + maxElements) < menuItemsCount) j++;
|
||||
|
||||
ypos = (8 + (breaks * LINE_HEIGHT) + (j * (font_height + 12)));
|
||||
|
||||
if (uiState == stateMainMenu)
|
||||
{
|
||||
j++;
|
||||
if ((scroll + maxElements) < menuItemsCount) j++;
|
||||
|
||||
// Print warning about missing Lockpick_RCM keys file
|
||||
if (!keysFileAvailable)
|
||||
{
|
||||
ypos = ((breaks * LINE_HEIGHT) + (j * (font_height + 12)));
|
||||
uiDrawString(STRING_X_POS, ypos, FONT_COLOR_ERROR_RGB, "Warning: missing keys file at \"%s\".", KEYS_FILE_PATH);
|
||||
j++;
|
||||
ypos += (LINE_HEIGHT + LINE_STRING_OFFSET);
|
||||
|
||||
ypos = ((breaks * LINE_HEIGHT) + (j * (font_height + 12)));
|
||||
uiDrawString(STRING_X_POS, ypos, FONT_COLOR_ERROR_RGB, "This file is needed to deal with the encryption schemes used by Nintendo Switch content files.");
|
||||
j++;
|
||||
ypos += (LINE_HEIGHT + LINE_STRING_OFFSET);
|
||||
|
||||
ypos = ((breaks * LINE_HEIGHT) + (j * (font_height + 12)));
|
||||
uiDrawString(STRING_X_POS, ypos, FONT_COLOR_ERROR_RGB, "SD/eMMC operations will be entirely disabled, along with NSP/ExeFS/RomFS related operations.");
|
||||
j++;
|
||||
ypos += (LINE_HEIGHT + LINE_STRING_OFFSET);
|
||||
|
||||
ypos = ((breaks * LINE_HEIGHT) + (j * (font_height + 12)));
|
||||
uiDrawString(STRING_X_POS, ypos, FONT_COLOR_ERROR_RGB, "Please run Lockpick_RCM to generate this file. More info at: https://github.com/shchmue/Lockpick_RCM");
|
||||
uiDrawString(STRING_X_POS, ypos, FONT_COLOR_ERROR_RGB, "Please run Lockpick_RCM to generate this file. More info at: " LOCKPICK_RCM_URL);
|
||||
}
|
||||
|
||||
// Print warning about running the application under applet mode
|
||||
if (programAppletType != AppletType_Application && programAppletType != AppletType_SystemApplication)
|
||||
if (appletModeCheck())
|
||||
{
|
||||
if (!keysFileAvailable) j += 2;
|
||||
if (!keysFileAvailable) ypos += ((LINE_HEIGHT * 2) + LINE_STRING_OFFSET);
|
||||
|
||||
ypos = ((breaks * LINE_HEIGHT) + (j * (font_height + 12)));
|
||||
uiDrawString(STRING_X_POS, ypos, FONT_COLOR_ERROR_RGB, "Warning: running under applet mode.");
|
||||
j++;
|
||||
ypos += (LINE_HEIGHT + LINE_STRING_OFFSET);
|
||||
|
||||
ypos = ((breaks * LINE_HEIGHT) + (j * (font_height + 12)));
|
||||
uiDrawString(STRING_X_POS, ypos, FONT_COLOR_ERROR_RGB, "It seems you used an applet (Album, Settings, etc.) to run the application. This mode greatly limits the amount of usable RAM.");
|
||||
j++;
|
||||
ypos += (LINE_HEIGHT + LINE_STRING_OFFSET);
|
||||
|
||||
ypos = ((breaks * LINE_HEIGHT) + (j * (font_height + 12)));
|
||||
uiDrawString(STRING_X_POS, ypos, FONT_COLOR_ERROR_RGB, "If you ever get any memory allocation errors, please consider running the application through title override (hold R while launching a game).");
|
||||
}
|
||||
}
|
||||
|
@ -2586,54 +2565,33 @@ UIResult uiProcess()
|
|||
// Print information about the "Change NPDM RSA key/sig in Program NCA" option
|
||||
if (((uiState == stateNspAppDumpMenu || uiState == stateNspPatchDumpMenu) && cursor == 5) || (uiState == stateSdCardEmmcBatchModeMenu && cursor == 7))
|
||||
{
|
||||
j++;
|
||||
if ((scroll + maxElements) < menuItemsCount) j++;
|
||||
|
||||
ypos = ((breaks * LINE_HEIGHT) + (j * (font_height + 12)));
|
||||
uiDrawString(STRING_X_POS, ypos, FONT_COLOR_RGB, "Replaces the public RSA key in the NPDM ACID section and the NPDM RSA signature in the Program NCA (only if it needs other modifications).");
|
||||
j++;
|
||||
ypos += (LINE_HEIGHT + LINE_STRING_OFFSET);
|
||||
|
||||
ypos = ((breaks * LINE_HEIGHT) + (j * (font_height + 12)));
|
||||
uiDrawString(STRING_X_POS, ypos, FONT_COLOR_RGB, "Disabling this will make the output NSP require ACID patches to work under any CFW, but will also make the Program NCA verifiable by PC tools.");
|
||||
}
|
||||
|
||||
// Print information about the "Dump delta fragments" option
|
||||
if ((uiState == stateNspPatchDumpMenu && cursor == 6) || (uiState == stateSdCardEmmcBatchModeMenu && cursor == 8))
|
||||
{
|
||||
j++;
|
||||
if ((scroll + maxElements) < menuItemsCount) j++;
|
||||
|
||||
ypos = ((breaks * LINE_HEIGHT) + (j * (font_height + 12)));
|
||||
uiDrawString(STRING_X_POS, ypos, FONT_COLOR_RGB, "Dumps delta fragments for the selected update(s), if available. These are commonly excluded - they serve no real purpose in output dumps.");
|
||||
}
|
||||
|
||||
// Print information about the "Split files bigger than 4 GiB (FAT32 support)" option
|
||||
if ((uiState == stateExeFsMenu || uiState == stateRomFsMenu) && cursor == 2)
|
||||
{
|
||||
j++;
|
||||
if ((scroll + maxElements) < menuItemsCount) j++;
|
||||
|
||||
ypos = ((breaks * LINE_HEIGHT) + (j * (font_height + 12)));
|
||||
uiDrawString(STRING_X_POS, ypos, FONT_COLOR_RGB, "If FAT32 support is enabled, files bigger than 4 GiB will be split and stored in a subdirectory with the archive bit set (like NSPs).");
|
||||
}
|
||||
|
||||
// Print information about the "Save data to CFW directory (LayeredFS)" option
|
||||
if ((uiState == stateExeFsMenu || uiState == stateRomFsMenu) && cursor == 3)
|
||||
{
|
||||
j++;
|
||||
if ((scroll + maxElements) < menuItemsCount) j++;
|
||||
|
||||
ypos = ((breaks * LINE_HEIGHT) + (j * (font_height + 12)));
|
||||
uiDrawString(STRING_X_POS, ypos, FONT_COLOR_RGB, "Enabling this option will save output data to \"%s[TitleID]/%s/\" (LayeredFS directory structure).", strchr(cfwDirStr, '/'), (uiState == stateExeFsMenu ? "exefs" : "romfs"));
|
||||
}
|
||||
|
||||
// Print hint about dumping RomFS content from DLCs
|
||||
if ((uiState == stateRomFsMenu && cursor == 4 && ((menuType == MENUTYPE_GAMECARD && titleAppCount <= 1 && checkIfBaseApplicationHasPatchOrAddOn(0, true)) || (menuType == MENUTYPE_SDCARD_EMMC && !orphanMode && checkIfBaseApplicationHasPatchOrAddOn(selectedAppInfoIndex, true)))) || ((uiState == stateRomFsSectionDataDumpMenu || uiState == stateRomFsSectionBrowserMenu) && cursor == 2 && (menuType == MENUTYPE_GAMECARD && titleAppCount > 1 && checkIfBaseApplicationHasPatchOrAddOn(selectedAppIndex, true))))
|
||||
{
|
||||
j++;
|
||||
if ((scroll + maxElements) < menuItemsCount) j++;
|
||||
|
||||
ypos = ((breaks * LINE_HEIGHT) + (j * (font_height + 12)));
|
||||
uiDrawString(STRING_X_POS, ypos, FONT_COLOR_RGB, "Hint: choosing a DLC will only access RomFS data from it, unlike updates (which share their RomFS data with its base application).");
|
||||
}
|
||||
} else {
|
||||
|
@ -2658,8 +2616,8 @@ UIResult uiProcess()
|
|||
|
||||
hidScanInput();
|
||||
|
||||
keysDown = hidKeysDown(CONTROLLER_P1_AUTO);
|
||||
keysHeld = hidKeysHeld(CONTROLLER_P1_AUTO);
|
||||
keysDown = hidKeysAllDown(CONTROLLER_P1_AUTO);
|
||||
keysHeld = hidKeysAllHeld(CONTROLLER_P1_AUTO);
|
||||
|
||||
if ((keysDown && !(keysDown & KEY_TOUCH)) || (keysHeld && !(keysHeld & KEY_TOUCH)) || (menuType == MENUTYPE_GAMECARD && gameCardInfo.isInserted != curGcStatus)) break;
|
||||
}
|
||||
|
@ -4167,12 +4125,14 @@ UIResult uiProcess()
|
|||
if (uiState == stateHfs0Browser)
|
||||
{
|
||||
freeHfs0ExeFsEntriesSizes();
|
||||
freeFilenameBuffer();
|
||||
|
||||
res = resultShowHfs0BrowserMenu;
|
||||
} else
|
||||
if (uiState == stateExeFsSectionBrowser)
|
||||
{
|
||||
freeHfs0ExeFsEntriesSizes();
|
||||
freeFilenameBuffer();
|
||||
|
||||
freeExeFsContext();
|
||||
|
||||
|
@ -4187,9 +4147,8 @@ UIResult uiProcess()
|
|||
res = resultRomFsSectionBrowserChangeDir;
|
||||
} else {
|
||||
freeRomFsBrowserEntries();
|
||||
|
||||
freeFilenameBuffer();
|
||||
if (curRomFsType == ROMFS_TYPE_PATCH) freeBktrContext();
|
||||
|
||||
freeRomFsContext();
|
||||
|
||||
res = ((menuType == MENUTYPE_GAMECARD && titleAppCount > 1) ? resultShowRomFsSectionBrowserMenu : resultShowRomFsMenu);
|
||||
|
@ -4279,9 +4238,7 @@ UIResult uiProcess()
|
|||
for(i = 0; i < scrollAmount; i++)
|
||||
{
|
||||
if (cursor >= (menuItemsCount - 1)) break;
|
||||
|
||||
cursor++;
|
||||
|
||||
if ((cursor - scroll) >= maxElements) scroll++;
|
||||
}
|
||||
}
|
||||
|
@ -4297,9 +4254,7 @@ UIResult uiProcess()
|
|||
for(i = 0; i < -scrollAmount; i++)
|
||||
{
|
||||
if (cursor <= 0) break;
|
||||
|
||||
cursor--;
|
||||
|
||||
if ((cursor - scroll) < 0) scroll--;
|
||||
}
|
||||
}
|
||||
|
@ -4415,13 +4370,82 @@ UIResult uiProcess()
|
|||
// Avoid placing the cursor on the "Dump base applications", "Dump updates" and/or "Dump DLCs" options in the batch mode menu if we're dealing with a storage source that doesn't hold any title belonging to the current category
|
||||
if (uiState == stateSdCardEmmcBatchModeMenu && ((dumpCfg.batchDumpCfg.batchModeSrc == BATCH_SOURCE_ALL && ((!titleAppCount && cursor == 1) || (!titlePatchCount && cursor == 2) || (!titleAddOnCount && cursor == 3))) || (dumpCfg.batchDumpCfg.batchModeSrc == BATCH_SOURCE_SDCARD && ((!sdCardTitleAppCount && cursor == 1) || (!sdCardTitlePatchCount && cursor == 2) || (!sdCardTitleAddOnCount && cursor == 3))) || (dumpCfg.batchDumpCfg.batchModeSrc == BATCH_SOURCE_EMMC && ((!emmcTitleAppCount && cursor == 1) || (!emmcTitlePatchCount && cursor == 2) || (!emmcTitleAddOnCount && cursor == 3)))))
|
||||
{
|
||||
if (scrollAmount > 0)
|
||||
if (cursor == 1)
|
||||
{
|
||||
cursor++;
|
||||
if (scrollAmount > 0)
|
||||
{
|
||||
if (dumpCfg.batchDumpCfg.batchModeSrc == BATCH_SOURCE_ALL)
|
||||
{
|
||||
cursor = (titlePatchCount ? 2 : (titleAddOnCount ? 3 : 4));
|
||||
} else
|
||||
if (dumpCfg.batchDumpCfg.batchModeSrc == BATCH_SOURCE_SDCARD)
|
||||
{
|
||||
cursor = (sdCardTitlePatchCount ? 2 : (sdCardTitleAddOnCount ? 3 : 4));
|
||||
} else
|
||||
if (dumpCfg.batchDumpCfg.batchModeSrc == BATCH_SOURCE_EMMC)
|
||||
{
|
||||
cursor = (emmcTitlePatchCount ? 2 : (emmcTitleAddOnCount ? 3 : 4));
|
||||
}
|
||||
} else
|
||||
if (scrollAmount < 0)
|
||||
{
|
||||
cursor = 0;
|
||||
}
|
||||
} else
|
||||
if (scrollAmount < 0)
|
||||
if (cursor == 2)
|
||||
{
|
||||
cursor--;
|
||||
if (scrollAmount > 0)
|
||||
{
|
||||
if (dumpCfg.batchDumpCfg.batchModeSrc == BATCH_SOURCE_ALL)
|
||||
{
|
||||
cursor = (titleAddOnCount ? 3 : 4);
|
||||
} else
|
||||
if (dumpCfg.batchDumpCfg.batchModeSrc == BATCH_SOURCE_SDCARD)
|
||||
{
|
||||
cursor = (sdCardTitleAddOnCount ? 3 : 4);
|
||||
} else
|
||||
if (dumpCfg.batchDumpCfg.batchModeSrc == BATCH_SOURCE_EMMC)
|
||||
{
|
||||
cursor = (emmcTitleAddOnCount ? 3 : 4);
|
||||
}
|
||||
} else
|
||||
if (scrollAmount < 0)
|
||||
{
|
||||
if (dumpCfg.batchDumpCfg.batchModeSrc == BATCH_SOURCE_ALL)
|
||||
{
|
||||
cursor = (titleAppCount ? 1 : 0);
|
||||
} else
|
||||
if (dumpCfg.batchDumpCfg.batchModeSrc == BATCH_SOURCE_SDCARD)
|
||||
{
|
||||
cursor = (sdCardTitleAppCount ? 1 : 0);
|
||||
} else
|
||||
if (dumpCfg.batchDumpCfg.batchModeSrc == BATCH_SOURCE_EMMC)
|
||||
{
|
||||
cursor = (emmcTitleAppCount ? 1 : 0);
|
||||
}
|
||||
}
|
||||
} else
|
||||
if (cursor == 3)
|
||||
{
|
||||
if (scrollAmount > 0)
|
||||
{
|
||||
cursor = 4;
|
||||
} else
|
||||
if (scrollAmount < 0)
|
||||
{
|
||||
if (dumpCfg.batchDumpCfg.batchModeSrc == BATCH_SOURCE_ALL)
|
||||
{
|
||||
cursor = (titlePatchCount ? 2 : (titleAppCount ? 1 : 0));
|
||||
} else
|
||||
if (dumpCfg.batchDumpCfg.batchModeSrc == BATCH_SOURCE_SDCARD)
|
||||
{
|
||||
cursor = (sdCardTitlePatchCount ? 2 : (sdCardTitleAppCount ? 1 : 0));
|
||||
} else
|
||||
if (dumpCfg.batchDumpCfg.batchModeSrc == BATCH_SOURCE_EMMC)
|
||||
{
|
||||
cursor = (emmcTitlePatchCount ? 2 : (emmcTitleAppCount ? 1 : 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4817,12 +4841,12 @@ UIResult uiProcess()
|
|||
} else
|
||||
if (uiState == stateHfs0BrowserCopyFile)
|
||||
{
|
||||
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_TITLE_RGB, "Manual File Dump: %s (HFS0 partition %u [%s])", filenames[selectedFileIndex], selectedPartitionIndex, GAMECARD_PARTITION_NAME(gameCardInfo.hfs0PartitionCnt, selectedPartitionIndex));
|
||||
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_TITLE_RGB, "Manual File Dump: %s (HFS0 partition %u [%s])", filenameBuffer[selectedFileIndex], selectedPartitionIndex, GAMECARD_PARTITION_NAME(gameCardInfo.hfs0PartitionCnt, selectedPartitionIndex));
|
||||
breaks += 2;
|
||||
|
||||
uiRefreshDisplay();
|
||||
|
||||
dumpFileFromHfs0Partition(selectedPartitionIndex, selectedFileIndex, filenames[selectedFileIndex], true);
|
||||
dumpFileFromHfs0Partition(selectedPartitionIndex, selectedFileIndex, filenameBuffer[selectedFileIndex], true);
|
||||
|
||||
waitForButtonPress();
|
||||
|
||||
|
@ -4906,7 +4930,7 @@ UIResult uiProcess()
|
|||
} else
|
||||
if (uiState == stateExeFsSectionBrowserCopyFile)
|
||||
{
|
||||
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_TITLE_RGB, "Manual File Dump: %s (ExeFS)", filenames[selectedFileIndex]);
|
||||
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_TITLE_RGB, "Manual File Dump: %s (ExeFS)", filenameBuffer[selectedFileIndex]);
|
||||
breaks++;
|
||||
|
||||
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_TITLE_RGB, "%s%s | %s%s", exeFsMenuItems[2], (dumpCfg.exeFsDumpCfg.isFat32 ? "Yes" : "No"), exeFsMenuItems[3], (dumpCfg.exeFsDumpCfg.useLayeredFSDir ? "Yes" : "No"));
|
||||
|
@ -5010,7 +5034,7 @@ UIResult uiProcess()
|
|||
|
||||
bool romfs_fail = false;
|
||||
|
||||
if (readNcaRomFsSection(curIndex, curRomFsType))
|
||||
if (readNcaRomFsSection(curIndex, curRomFsType, -1))
|
||||
{
|
||||
if (getRomFsFileList(0, (curRomFsType == ROMFS_TYPE_PATCH)))
|
||||
{
|
||||
|
@ -5076,6 +5100,7 @@ UIResult uiProcess()
|
|||
if (romfs_fail)
|
||||
{
|
||||
freeRomFsBrowserEntries();
|
||||
freeFilenameBuffer();
|
||||
if (curRomFsType == ROMFS_TYPE_PATCH) freeBktrContext();
|
||||
freeRomFsContext();
|
||||
|
||||
|
@ -5088,7 +5113,7 @@ UIResult uiProcess()
|
|||
{
|
||||
u32 curIndex = 0;
|
||||
|
||||
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_TITLE_RGB, "Manual File Dump: %s (RomFS)", filenames[selectedFileIndex]);
|
||||
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_TITLE_RGB, "Manual File Dump: %s (RomFS)", filenameBuffer[selectedFileIndex]);
|
||||
breaks++;
|
||||
|
||||
uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_TITLE_RGB, "%s%s | %s%s", romFsMenuItems[2], (dumpCfg.romFsDumpCfg.isFat32 ? "Yes" : "No"), romFsMenuItems[3], (dumpCfg.romFsDumpCfg.useLayeredFSDir ? "Yes" : "No"));
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#define STRING_DEFAULT_POS 8, 8
|
||||
|
||||
#define STRING_X_POS 8
|
||||
#define STRING_Y_POS(x) (((x) * LINE_HEIGHT) + LINE_STRING_OFFSET)
|
||||
#define STRING_Y_POS(x) (8 + ((x) * LINE_HEIGHT) + ((x) > 0 ? LINE_STRING_OFFSET : 0))
|
||||
|
||||
#define BG_COLOR_RGB 50, 50, 50
|
||||
#define FONT_COLOR_RGB 255, 255, 255
|
||||
|
|
916
source/util.c
916
source/util.c
File diff suppressed because it is too large
Load diff
|
@ -6,28 +6,51 @@
|
|||
#include <switch.h>
|
||||
#include "nca.h"
|
||||
|
||||
#define APP_BASE_PATH "sdmc:/switch/"
|
||||
#define NXDUMPTOOL_BASE_PATH APP_BASE_PATH "nxdumptool/"
|
||||
#define XCI_DUMP_PATH NXDUMPTOOL_BASE_PATH "XCI/"
|
||||
#define NSP_DUMP_PATH NXDUMPTOOL_BASE_PATH "NSP/"
|
||||
#define HFS0_DUMP_PATH NXDUMPTOOL_BASE_PATH "HFS0/"
|
||||
#define EXEFS_DUMP_PATH NXDUMPTOOL_BASE_PATH "ExeFS/"
|
||||
#define ROMFS_DUMP_PATH NXDUMPTOOL_BASE_PATH "RomFS/"
|
||||
#define CERT_DUMP_PATH NXDUMPTOOL_BASE_PATH "Certificate/"
|
||||
#define HBLOADER_BASE_PATH "sdmc:/switch/"
|
||||
#define APP_BASE_PATH HBLOADER_BASE_PATH APP_TITLE "/"
|
||||
#define XCI_DUMP_PATH APP_BASE_PATH "XCI/"
|
||||
#define NSP_DUMP_PATH APP_BASE_PATH "NSP/"
|
||||
#define HFS0_DUMP_PATH APP_BASE_PATH "HFS0/"
|
||||
#define EXEFS_DUMP_PATH APP_BASE_PATH "ExeFS/"
|
||||
#define ROMFS_DUMP_PATH APP_BASE_PATH "RomFS/"
|
||||
#define CERT_DUMP_PATH APP_BASE_PATH "Certificate/"
|
||||
#define BATCH_OVERRIDES_PATH NSP_DUMP_PATH "BatchOverrides/"
|
||||
#define TICKET_PATH NXDUMPTOOL_BASE_PATH "Ticket/"
|
||||
#define TICKET_PATH APP_BASE_PATH "Ticket/"
|
||||
|
||||
#define KEYS_FILE_PATH APP_BASE_PATH "prod.keys"
|
||||
#define CONFIG_PATH APP_BASE_PATH "config.bin"
|
||||
#define NRO_NAME APP_TITLE ".nro"
|
||||
#define NRO_PATH APP_BASE_PATH NRO_NAME
|
||||
#define NSWDB_XML_PATH APP_BASE_PATH "NSWreleases.xml"
|
||||
#define KEYS_FILE_PATH HBLOADER_BASE_PATH "prod.keys"
|
||||
|
||||
#define CFW_PATH_ATMOSPHERE "sdmc:/atmosphere/contents/"
|
||||
#define CFW_PATH_SXOS "sdmc:/sxos/titles/"
|
||||
#define CFW_PATH_REINX "sdmc:/ReiNX/titles/"
|
||||
|
||||
#define HTTP_USER_AGENT APP_TITLE "/" APP_VERSION " (Nintendo Switch)"
|
||||
|
||||
#define GITHUB_API_URL "https://api.github.com/repos/DarkMatterCore/nxdumptool/releases/latest"
|
||||
#define GITHUB_API_JSON_RELEASE_NAME "name"
|
||||
#define GITHUB_API_JSON_ASSETS "assets"
|
||||
#define GITHUB_API_JSON_ASSETS_NAME "name"
|
||||
#define GITHUB_API_JSON_ASSETS_DL_URL "browser_download_url"
|
||||
|
||||
#define NOINTRO_DOM_CHECK_URL "https://datomatic.no-intro.org/qchknsw.php"
|
||||
|
||||
#define NSWDB_XML_URL "http://nswdb.com/xml.php"
|
||||
#define NSWDB_XML_ROOT "releases"
|
||||
#define NSWDB_XML_CHILD "release"
|
||||
#define NSWDB_XML_CHILD_TITLEID "titleid"
|
||||
#define NSWDB_XML_CHILD_IMGCRC "imgcrc"
|
||||
#define NSWDB_XML_CHILD_RELEASENAME "releasename"
|
||||
|
||||
#define LOCKPICK_RCM_URL "https://github.com/shchmue/Lockpick_RCM"
|
||||
|
||||
#define KiB (1024.0)
|
||||
#define MiB (1024.0 * KiB)
|
||||
#define GiB (1024.0 * MiB)
|
||||
|
||||
#define NAME_BUF_LEN 4096
|
||||
#define NAME_BUF_LEN 2048
|
||||
|
||||
#define DUMP_BUFFER_SIZE (u64)0x400000 // 4 MiB (4194304 bytes)
|
||||
|
||||
|
@ -40,10 +63,6 @@
|
|||
#define APPLICATION_PATCH_BITMASK (u64)0x800
|
||||
#define APPLICATION_ADDON_BITMASK (u64)0xFFFFFFFFFFFF0000
|
||||
|
||||
#define FILENAME_LENGTH 512
|
||||
#define FILENAME_MAX_CNT 20000
|
||||
#define FILENAME_BUFFER_SIZE (FILENAME_LENGTH * FILENAME_MAX_CNT) // 10000 KiB
|
||||
|
||||
#define NACP_APPNAME_LEN 0x200
|
||||
#define NACP_AUTHOR_LEN 0x100
|
||||
#define VERSION_STR_LEN 0x40
|
||||
|
@ -82,7 +101,6 @@
|
|||
#define NACP_ICON_SQUARE_DIMENSION 256
|
||||
#define NACP_ICON_DOWNSCALED 96
|
||||
|
||||
#define bswap_32(a) ((((a) << 24) & 0xff000000) | (((a) << 8) & 0xff0000) | (((a) >> 8) & 0xff00) | (((a) >> 24) & 0xff))
|
||||
#define round_up(x, y) ((x) + (((y) - ((x) % (y))) % (y))) // Aligns 'x' bytes to a 'y' bytes boundary
|
||||
|
||||
#define ORPHAN_ENTRY_TYPE_PATCH 1
|
||||
|
@ -159,7 +177,7 @@ typedef struct {
|
|||
u64 updateTitleId;
|
||||
u32 updateVersion;
|
||||
char updateVersionStr[64];
|
||||
} PACKED gamecard_ctx_t;
|
||||
} gamecard_ctx_t;
|
||||
|
||||
typedef struct {
|
||||
u64 titleId;
|
||||
|
@ -173,7 +191,7 @@ typedef struct {
|
|||
u8 *icon;
|
||||
u64 contentSize;
|
||||
char contentSizeStr[32];
|
||||
} PACKED base_app_ctx_t;
|
||||
} base_app_ctx_t;
|
||||
|
||||
typedef struct {
|
||||
u64 titleId;
|
||||
|
@ -183,7 +201,7 @@ typedef struct {
|
|||
char versionStr[VERSION_STR_LEN];
|
||||
u64 contentSize;
|
||||
char contentSizeStr[32];
|
||||
} PACKED patch_addon_ctx_t;
|
||||
} patch_addon_ctx_t;
|
||||
|
||||
typedef struct {
|
||||
u32 index;
|
||||
|
@ -191,7 +209,7 @@ typedef struct {
|
|||
char name[NACP_APPNAME_LEN];
|
||||
char fixedName[NACP_APPNAME_LEN];
|
||||
char orphanListStr[NACP_APPNAME_LEN * 2];
|
||||
} PACKED orphan_patch_addon_entry;
|
||||
} orphan_patch_addon_entry;
|
||||
|
||||
typedef struct {
|
||||
u32 magic;
|
||||
|
@ -227,7 +245,7 @@ typedef struct {
|
|||
u32 cancelBtnStatePrev;
|
||||
u64 cancelStartTmr;
|
||||
u64 cancelEndTmr;
|
||||
} PACKED progress_ctx_t;
|
||||
} progress_ctx_t;
|
||||
|
||||
typedef enum {
|
||||
ROMFS_TYPE_APP = 0,
|
||||
|
@ -314,6 +332,8 @@ void delay(u8 seconds);
|
|||
void convertSize(u64 size, char *out, size_t outSize);
|
||||
void updateFreeSpace();
|
||||
|
||||
void freeFilenameBuffer(void);
|
||||
|
||||
void initExeFsContext();
|
||||
void freeExeFsContext();
|
||||
|
||||
|
@ -326,13 +346,18 @@ void freeBktrContext();
|
|||
void freeRomFsBrowserEntries();
|
||||
void freeHfs0ExeFsEntriesSizes();
|
||||
|
||||
u64 hidKeysAllDown();
|
||||
u64 hidKeysAllHeld();
|
||||
|
||||
void consoleErrorScreen(const char *fmt, ...);
|
||||
bool initApplicationResources(int argc, char **argv);
|
||||
void deinitApplicationResources();
|
||||
|
||||
void formatETAString(u64 curTime, char *out, size_t outSize);
|
||||
bool appletModeCheck();
|
||||
void appletModeOperationWarning();
|
||||
void changeHomeButtonBlockStatus(bool block);
|
||||
|
||||
void addStringToFilenameBuffer(const char *string);
|
||||
void formatETAString(u64 curTime, char *out, size_t outSize);
|
||||
|
||||
void generateSdCardEmmcTitleList();
|
||||
|
||||
|
@ -363,7 +388,7 @@ void removeConsoleDataFromTicket(title_rights_ctx *rights_info);
|
|||
|
||||
bool readNcaExeFsSection(u32 titleIndex, bool usePatch);
|
||||
|
||||
bool readNcaRomFsSection(u32 titleIndex, selectedRomFsType curRomFsType);
|
||||
bool readNcaRomFsSection(u32 titleIndex, selectedRomFsType curRomFsType, int desiredIdOffset);
|
||||
|
||||
bool getExeFsFileList();
|
||||
|
||||
|
|
Loading…
Reference in a new issue