1
0
Fork 0
mirror of https://github.com/DarkMatterCore/nxdumptool.git synced 2024-11-29 21:52:22 +00:00

Update to v1.1.4.

This commit is contained in:
Pablo Curiel 2019-08-15 01:21:51 -04:00
parent a051b17ad0
commit ed45a863fa
11 changed files with 295 additions and 280 deletions

View file

@ -33,7 +33,7 @@ include $(DEVKITPRO)/libnx/switch_rules
VERSION_MAJOR := 1 VERSION_MAJOR := 1
VERSION_MINOR := 1 VERSION_MINOR := 1
VERSION_MICRO := 3 VERSION_MICRO := 4
APP_TITLE := nxdumptool APP_TITLE := nxdumptool
APP_AUTHOR := MCMrARM, DarkMatterCore APP_AUTHOR := MCMrARM, DarkMatterCore

View file

@ -4,24 +4,25 @@ Nintendo Switch Dump Tool
Main features Main features
-------------- --------------
* Generates full Cartridge Image dumps (XCI) with optional certificate removal and optional trimming. * Generates full Cartridge Image dumps (XCI) 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. * 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. * The generated dumps follow the `AuditingTool` format from Scene releases.
* Capable of generating ticket-less (standard crypto) dumps.
* Capable of generating dumps from installed updates/DLCs with missing base applications (orphan titles).
* Compatible with multigame carts. * Compatible with multigame carts.
* CRC32 checksum calculation for XCI/NSP dumps. * CRC32 checksum calculation for XCI/NSP dumps.
* Full XCI dump verification using XML database from NSWDB.COM (NSWreleases.xml). * Full XCI dump verification using XML database from NSWDB.COM (NSWreleases.xml).
* XML database and in-app update via libcurl. * XML database and in-app update capabilities via libcurl.
* Precise HFS0 raw partition dumping, using the root HFS0 header from the game card. * Precise HFS0 raw partition dumping, using the root HFS0 header from the gamecard.
* HFS0 partition file data dumping. * HFS0 partition file data dumping + browser with manual file dump support.
* HFS0 partition file browser with manual file dump support. * Program NCA ExeFS/RomFS section file data dumping + browser with manual file dump support.
* Program NCA ExeFS section file data dumping. * Compatible with both base applications and updates (if available).
* Program NCA ExeFS section file browser with manual file dump support. * Supports manual RomFS directory dumping.
* Program NCA RomFS section file data dumping. * Manual gamecard certificate dump.
* Program NCA RomFS section file browser with manual file dump support.
* Manual game card certificate dump.
* Free SD card space checks in place. * Free SD card space checks in place.
* File splitting support for all operations. * File splitting support for all operations.
* Game card metadata retrieval using NCM and NS services. * Capable of storing split XCI/NSP dumps in directories with the archive bit set.
* Metadata retrieval using NCM and NS services.
* Dump speed calculation, ETA calculation and progress bar. * Dump speed calculation, ETA calculation and progress bar.
Operations related to installed SD/eMMC titles require a keys file located at "sdmc:/switch/prod.keys". Use [Lockpick_RCM](https://github.com/shchmue/Lockpick_RCM) to generate it. Operations related to installed SD/eMMC titles require a keys file located at "sdmc:/switch/prod.keys". Use [Lockpick_RCM](https://github.com/shchmue/Lockpick_RCM) to generate it.
@ -58,6 +59,15 @@ If you like my work and you'd like to support me in any way, it's not necessary,
Changelog Changelog
-------------- --------------
**v1.1.4:**
* Fixed building with latest libnx release.
* Optimized RomFS recursive file dump function to not rely on code recursion as much as before, avoiding stack memory exhaustion problems. Fixes crashes while dumping RomFS data from games with lots of file entries.
* Reduced max part size for split files to `0xFFFF0000` bytes in all operations (except for XCI dumps when the "Create directory with archive bit set" option is disabled). Fixes file access problems if the parts are used inside a directory with the archive bit set.
* Removed the `removeDirectory()` function. `fsdevDeleteDirectoryRecursively()` is now used instead.
* If a HFS0/ExeFS/RomFS data dump operation is cancelled or fails, a message telling the user to wait until the output directory is fully deleted will now be displayed.
* Improved the cancel button detection mechanism. Regardless of the ongoing operation, holding the button for 2 seconds will now consistently cancel it.
* Progress bar movement is now smoother.
**v1.1.3:** **v1.1.3:**
* General changes to the NSP dumping procedure: * General changes to the NSP dumping procedure:
* Corrected and updated CNMT XML and NACP XML generation. Thanks to [0Liam](https://github.com/0Liam)! * Corrected and updated CNMT XML and NACP XML generation. Thanks to [0Liam](https://github.com/0Liam)!
@ -238,9 +248,9 @@ Big thanks to PatrickD85, unvaluablespace, wartutor and Slim45 for testing these
**v1.0.5:** **v1.0.5:**
* Fixed game card version reading (now using the ncm service instead of retrieving it from the cached Control.nacp). * Fixed gamecard version reading (now using the ncm service instead of retrieving it from the cached Control.nacp).
* Added ability to read and identify FW update versions bundled with game cards. * Added ability to read and identify FW update versions bundled with gamecards.
* In case an error occurs while reading the game card Title ID, the application will also display the FW version update bundled with it along with an explanation. * In case an error occurs while reading the gamecard Title ID, the application will also display the FW version update bundled with it along with an explanation.
* Removed output XCI dump renaming based on the XML database from nswdb.com. * Removed output XCI dump renaming based on the XML database from nswdb.com.
* Output naming scheme changed. Characters out of the ASCII range are replaced with underscores: * Output naming scheme changed. Characters out of the ASCII range are replaced with underscores:
- XCI dump: "sdmc:/[GameName] v[GameVersion] ([TitleID]).xci". - XCI dump: "sdmc:/[GameName] v[GameVersion] ([TitleID]).xci".

View file

@ -106,6 +106,8 @@ bool dumpCartridgeImage(bool isFat32, bool setXciArchiveBit, bool dumpCert, bool
size_t write_res; size_t write_res;
u64 part_size = (!setXciArchiveBit ? SPLIT_FILE_XCI_PART_SIZE : SPLIT_FILE_NSP_PART_SIZE);
char *dumpName = generateFullDumpName(); char *dumpName = generateFullDumpName();
if (!dumpName) if (!dumpName)
{ {
@ -254,7 +256,7 @@ bool dumpCartridgeImage(bool isFat32, bool setXciArchiveBit, bool dumpCert, bool
// Since we may actually be dealing with an existing directory with the archive bit set or unset, let's try both // Since we may actually be dealing with an existing directory with the archive bit set or unset, let's try both
// Better safe than sorry // Better safe than sorry
unlink(filename); unlink(filename);
removeDirectory(filename); fsdevDeleteDirectoryRecursively(filename);
mkdir(filename, 0744); mkdir(filename, 0744);
@ -354,9 +356,9 @@ bool dumpCartridgeImage(bool isFat32, bool setXciArchiveBit, bool dumpCert, bool
} }
} }
if (progressCtx.totalSize > FAT32_FILESIZE_LIMIT && isFat32 && (progressCtx.curOffset + n) >= ((splitIndex + 1) * SPLIT_FILE_XCI_PART_SIZE)) if (progressCtx.totalSize > FAT32_FILESIZE_LIMIT && isFat32 && (progressCtx.curOffset + n) >= ((splitIndex + 1) * part_size))
{ {
u64 new_file_chunk_size = ((progressCtx.curOffset + n) - ((splitIndex + 1) * SPLIT_FILE_XCI_PART_SIZE)); u64 new_file_chunk_size = ((progressCtx.curOffset + n) - ((splitIndex + 1) * part_size));
u64 old_file_chunk_size = (n - new_file_chunk_size); u64 old_file_chunk_size = (n - new_file_chunk_size);
if (old_file_chunk_size > 0) if (old_file_chunk_size > 0)
@ -426,12 +428,9 @@ bool dumpCartridgeImage(bool isFat32, bool setXciArchiveBit, bool dumpCert, bool
printProgressBar(&progressCtx, true, n); printProgressBar(&progressCtx, true, n);
if ((progressCtx.curOffset + n) < progressCtx.totalSize && ((progressCtx.curOffset / DUMP_BUFFER_SIZE) % 10) == 0) if ((progressCtx.curOffset + n) < progressCtx.totalSize)
{ {
hidScanInput(); if (cancelProcessCheck(&progressCtx))
u32 keysDown = hidKeysDown(CONTROLLER_P1_AUTO);
if (keysDown & KEY_B)
{ {
uiDrawString("Process canceled.", 8, ((progressCtx.line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0); uiDrawString("Process canceled.", 8, ((progressCtx.line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0);
proceed = false; proceed = false;
@ -546,7 +545,7 @@ bool dumpCartridgeImage(bool isFat32, bool setXciArchiveBit, bool dumpCert, bool
if (setXciArchiveBit) if (setXciArchiveBit)
{ {
snprintf(filename, sizeof(filename) / sizeof(filename[0]), "%s%s.xci", XCI_DUMP_PATH, dumpName); snprintf(filename, sizeof(filename) / sizeof(filename[0]), "%s%s.xci", XCI_DUMP_PATH, dumpName);
removeDirectory(filename); fsdevDeleteDirectoryRecursively(filename);
} else { } else {
for(u8 i = 0; i <= splitIndex; i++) for(u8 i = 0; i <= splitIndex; i++)
{ {
@ -1322,7 +1321,7 @@ bool dumpNintendoSubmissionPackage(nspDumpType selectedNspDumpType, u32 titleInd
// Since we may actually be dealing with an existing directory with the archive bit set or unset, let's try both // Since we may actually be dealing with an existing directory with the archive bit set or unset, let's try both
// Better safe than sorry // Better safe than sorry
unlink(dumpPath); unlink(dumpPath);
removeDirectory(dumpPath); fsdevDeleteDirectoryRecursively(dumpPath);
if (progressCtx.totalSize > FAT32_FILESIZE_LIMIT && isFat32) if (progressCtx.totalSize > FAT32_FILESIZE_LIMIT && isFat32)
{ {
@ -1556,12 +1555,9 @@ bool dumpNintendoSubmissionPackage(nspDumpType selectedNspDumpType, u32 titleInd
printProgressBar(&progressCtx, true, n); printProgressBar(&progressCtx, true, n);
if ((progressCtx.curOffset + n) < progressCtx.totalSize && ((progressCtx.curOffset / DUMP_BUFFER_SIZE) % 10) == 0) if ((progressCtx.curOffset + n) < progressCtx.totalSize)
{ {
hidScanInput(); if (cancelProcessCheck(&progressCtx))
u32 keysDown = hidKeysDown(CONTROLLER_P1_AUTO);
if (keysDown & KEY_B)
{ {
uiDrawString("Process canceled.", 8, ((progressCtx.line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0); uiDrawString("Process canceled.", 8, ((progressCtx.line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0);
proceed = false; proceed = false;
@ -1919,12 +1915,9 @@ bool dumpNintendoSubmissionPackage(nspDumpType selectedNspDumpType, u32 titleInd
printProgressBar(&progressCtx, true, n); printProgressBar(&progressCtx, true, n);
if ((progressCtx.curOffset + n) < progressCtx.totalSize && ((progressCtx.curOffset / DUMP_BUFFER_SIZE) % 10) == 0) if ((progressCtx.curOffset + n) < progressCtx.totalSize)
{ {
hidScanInput(); if (cancelProcessCheck(&progressCtx))
u32 keysDown = hidKeysDown(CONTROLLER_P1_AUTO);
if (keysDown & KEY_B)
{ {
uiDrawString("Process canceled.", 8, ((progressCtx.line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0); uiDrawString("Process canceled.", 8, ((progressCtx.line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0);
proceed = false; proceed = false;
@ -2101,12 +2094,9 @@ bool dumpNintendoSubmissionPackage(nspDumpType selectedNspDumpType, u32 titleInd
printProgressBar(&progressCtx, true, n); printProgressBar(&progressCtx, true, n);
if ((progressCtx.curOffset + n) < progressCtx.totalSize && ((progressCtx.curOffset / DUMP_BUFFER_SIZE) % 10) == 0) if ((progressCtx.curOffset + n) < progressCtx.totalSize)
{ {
hidScanInput(); if (cancelProcessCheck(&progressCtx))
u32 keysDown = hidKeysDown(CONTROLLER_P1_AUTO);
if (keysDown & KEY_B)
{ {
uiDrawString("Process canceled.", 8, ((progressCtx.line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0); uiDrawString("Process canceled.", 8, ((progressCtx.line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0);
proceed = false; proceed = false;
@ -2168,7 +2158,7 @@ out:
if (progressCtx.totalSize > FAT32_FILESIZE_LIMIT && isFat32) if (progressCtx.totalSize > FAT32_FILESIZE_LIMIT && isFat32)
{ {
removeDirectory(dumpPath); fsdevDeleteDirectoryRecursively(dumpPath);
} else { } else {
unlink(dumpPath); unlink(dumpPath);
} }
@ -2832,12 +2822,9 @@ bool dumpRawHfs0Partition(u32 partition, bool doSplitting)
printProgressBar(&progressCtx, true, n); printProgressBar(&progressCtx, true, n);
if ((progressCtx.curOffset + n) < progressCtx.totalSize && ((progressCtx.curOffset / DUMP_BUFFER_SIZE) % 10) == 0) if ((progressCtx.curOffset + n) < progressCtx.totalSize)
{ {
hidScanInput(); if (cancelProcessCheck(&progressCtx))
u32 keysDown = hidKeysDown(CONTROLLER_P1_AUTO);
if (keysDown & KEY_B)
{ {
uiDrawString("Process canceled.", 8, ((progressCtx.line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0); uiDrawString("Process canceled.", 8, ((progressCtx.line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0);
break; break;
@ -3048,12 +3035,9 @@ bool copyFileFromHfs0(u32 partition, const char* source, const char* dest, const
printProgressBar(progressCtx, true, n); printProgressBar(progressCtx, true, n);
if ((off + n) < size && ((off / DUMP_BUFFER_SIZE) % 10) == 0) if ((off + n) < size || (progressCtx->curOffset + n) < progressCtx->totalSize)
{ {
hidScanInput(); if (cancelProcessCheck(progressCtx))
u32 keysDown = hidKeysDown(CONTROLLER_P1_AUTO);
if (keysDown & KEY_B)
{ {
uiDrawString("Process canceled.", 8, ((progressCtx->line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0); uiDrawString("Process canceled.", 8, ((progressCtx->line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0);
break; break;
@ -3251,7 +3235,7 @@ bool dumpHfs0PartitionData(u32 partition, bool doSplitting)
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Process successfully completed after %s!", progressCtx.etaInfo); snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Process successfully completed after %s!", progressCtx.etaInfo);
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 0, 255, 0); uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 0, 255, 0);
} else { } else {
removeDirectory(dumpPath); removeDirectoryWithVerbose(dumpPath, "Deleting output directory. Please wait...");
} }
} else { } else {
uiDrawString("Error: not enough free space available in the SD card.", 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0); uiDrawString("Error: not enough free space available in the SD card.", 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0);
@ -3629,12 +3613,9 @@ bool dumpExeFsSectionData(u32 titleIndex, bool usePatch, bool doSplitting)
printProgressBar(&progressCtx, true, n); printProgressBar(&progressCtx, true, n);
if ((progressCtx.curOffset + n) < progressCtx.totalSize && ((progressCtx.curOffset / DUMP_BUFFER_SIZE) % 10) == 0) if ((progressCtx.curOffset + n) < progressCtx.totalSize)
{ {
hidScanInput(); if (cancelProcessCheck(&progressCtx))
u32 keysDown = hidKeysDown(CONTROLLER_P1_AUTO);
if (keysDown & KEY_B)
{ {
uiDrawString("Process canceled.", 8, ((progressCtx.line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0); uiDrawString("Process canceled.", 8, ((progressCtx.line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0);
proceed = false; proceed = false;
@ -3686,8 +3667,8 @@ bool dumpExeFsSectionData(u32 titleIndex, bool usePatch, bool doSplitting)
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 0, 255, 0); uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 0, 255, 0);
} else { } else {
setProgressBarError(&progressCtx); setProgressBarError(&progressCtx);
removeDirectory(dumpPath);
if (fat32_error) breaks += 2; if (fat32_error) breaks += 2;
removeDirectoryWithVerbose(dumpPath, "Deleting output directory. Please wait...");
} }
out: out:
@ -3916,12 +3897,9 @@ bool dumpFileFromExeFsSection(u32 titleIndex, u32 fileIndex, bool usePatch, bool
printProgressBar(&progressCtx, true, n); printProgressBar(&progressCtx, true, n);
if ((progressCtx.curOffset + n) < progressCtx.totalSize && ((progressCtx.curOffset / DUMP_BUFFER_SIZE) % 10) == 0) if ((progressCtx.curOffset + n) < progressCtx.totalSize)
{ {
hidScanInput(); if (cancelProcessCheck(&progressCtx))
u32 keysDown = hidKeysDown(CONTROLLER_P1_AUTO);
if (keysDown & KEY_B)
{ {
uiDrawString("Process canceled.", 8, ((progressCtx.line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0); uiDrawString("Process canceled.", 8, ((progressCtx.line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0);
break; break;
@ -4010,183 +3988,203 @@ bool recursiveDumpRomFsFile(u32 file_offset, char *romfs_path, char *output_path
u8 splitIndex = 0; u8 splitIndex = 0;
bool proceed = true, success = false, fat32_error = false; bool proceed = true, success = false, fat32_error = false;
u32 romfs_file_offset = file_offset;
romfs_file *entry = NULL;
u64 off = 0; u64 off = 0;
size_t write_res; size_t write_res;
char tmp_idx[5]; char tmp_idx[5];
romfs_file *entry = (!usePatch ? (romfs_file*)((u8*)romFsContext.romfs_file_entries + file_offset) : (romfs_file*)((u8*)bktrContext.romfs_file_entries + file_offset));
// Check if we're dealing with a nameless file
if (!entry->nameLen)
{
uiDrawString("Error: file entry without name in RomFS section!", 8, ((progressCtx->line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0);
return false;
}
if ((orig_romfs_path_len + 1 + entry->nameLen) >= (NAME_BUF_LEN * 2) || (orig_output_path_len + 1 + entry->nameLen) >= (NAME_BUF_LEN * 2))
{
uiDrawString("Error: RomFS section file path is too long!", 8, ((progressCtx->line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0);
return false;
}
// Generate current path
strcat(romfs_path, "/");
strncat(romfs_path, (char*)entry->name, entry->nameLen);
strcat(output_path, "/");
strncat(output_path, (char*)entry->name, entry->nameLen);
removeIllegalCharacters(output_path + orig_output_path_len + 1);
// Start dump process
uiFill(0, ((progressCtx->line_offset - 4) * (font_height + (font_height / 4))) + 8, FB_WIDTH, (font_height + (font_height / 4)) * 4, BG_COLOR_RGB, BG_COLOR_RGB, BG_COLOR_RGB);
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Copying \"romfs:%s\"...", romfs_path);
uiDrawString(strbuf, 8, ((progressCtx->line_offset - 4) * (font_height + (font_height / 4))) + (font_height / 8), 255, 255, 255);
if (entry->dataSize > FAT32_FILESIZE_LIMIT && doSplitting)
{
sprintf(tmp_idx, ".%02u", splitIndex);
strcat(output_path, tmp_idx);
}
outFile = fopen(output_path, "wb");
if (!outFile)
{
uiDrawString("Failed to open output file!", 8, ((progressCtx->line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 255, 255);
goto out;
}
buf = malloc(DUMP_BUFFER_SIZE); buf = malloc(DUMP_BUFFER_SIZE);
if (!buf) if (!buf)
{ {
uiDrawString("Failed to allocate memory for the dump process!", 8, ((progressCtx->line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 255, 255); uiDrawString("Failed to allocate memory for the dump process!", 8, ((progressCtx->line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 255, 255);
goto out; return false;
} }
for(off = 0; off < entry->dataSize; off += n, progressCtx->curOffset += n) while(romfs_file_offset != ROMFS_ENTRY_EMPTY)
{ {
uiFill(0, ((progressCtx->line_offset - 2) * (font_height + (font_height / 4))) + 8, FB_WIDTH, (font_height + (font_height / 4)) * 2, BG_COLOR_RGB, BG_COLOR_RGB, BG_COLOR_RGB); romfs_path[orig_romfs_path_len] = '\0';
output_path[orig_output_path_len] = '\0';
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Output file: \"%s\".", strrchr(output_path, '/') + 1); entry = (!usePatch ? (romfs_file*)((u8*)romFsContext.romfs_file_entries + romfs_file_offset) : (romfs_file*)((u8*)bktrContext.romfs_file_entries + romfs_file_offset));
uiDrawString(strbuf, 8, ((progressCtx->line_offset - 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 255, 255);
uiRefreshDisplay(); // Check if we're dealing with a nameless file
if (!entry->nameLen)
if (DUMP_BUFFER_SIZE > (entry->dataSize - off)) n = (entry->dataSize - off);
breaks = (progressCtx->line_offset + 2);
if (!usePatch)
{ {
proceed = processNcaCtrSectionBlock(&(romFsContext.ncmStorage), &(romFsContext.ncaId), &(romFsContext.aes_ctx), romFsContext.romfs_filedata_offset + entry->dataOff + off, buf, n, false); uiDrawString("Error: file entry without name in RomFS section!", 8, ((progressCtx->line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0);
} else { break;
proceed = readBktrSectionBlock(bktrContext.romfs_filedata_offset + entry->dataOff + off, buf, n);
} }
breaks = (progressCtx->line_offset - 4); if ((orig_romfs_path_len + 1 + entry->nameLen) >= (NAME_BUF_LEN * 2) || (orig_output_path_len + 1 + entry->nameLen) >= (NAME_BUF_LEN * 2))
if (!proceed) break;
if (entry->dataSize > FAT32_FILESIZE_LIMIT && doSplitting && (off + n) >= ((splitIndex + 1) * SPLIT_FILE_GENERIC_PART_SIZE))
{ {
u64 new_file_chunk_size = ((off + n) - ((splitIndex + 1) * SPLIT_FILE_GENERIC_PART_SIZE)); uiDrawString("Error: RomFS section file path is too long!", 8, ((progressCtx->line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0);
u64 old_file_chunk_size = (n - new_file_chunk_size); break;
}
if (old_file_chunk_size > 0) // Generate current path
strcat(romfs_path, "/");
strncat(romfs_path, (char*)entry->name, entry->nameLen);
strcat(output_path, "/");
strncat(output_path, (char*)entry->name, entry->nameLen);
removeIllegalCharacters(output_path + orig_output_path_len + 1);
// Start dump process
uiFill(0, ((progressCtx->line_offset - 4) * (font_height + (font_height / 4))) + 8, FB_WIDTH, (font_height + (font_height / 4)) * 4, BG_COLOR_RGB, BG_COLOR_RGB, BG_COLOR_RGB);
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Copying \"romfs:%s\"...", romfs_path);
uiDrawString(strbuf, 8, ((progressCtx->line_offset - 4) * (font_height + (font_height / 4))) + (font_height / 8), 255, 255, 255);
if (entry->dataSize > FAT32_FILESIZE_LIMIT && doSplitting)
{
sprintf(tmp_idx, ".%02u", splitIndex);
strcat(output_path, tmp_idx);
}
outFile = fopen(output_path, "wb");
if (!outFile)
{
uiDrawString("Failed to open output file!", 8, ((progressCtx->line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 255, 255);
break;
}
n = DUMP_BUFFER_SIZE;
splitIndex = 0;
for(off = 0; off < entry->dataSize; off += n, progressCtx->curOffset += n)
{
uiFill(0, ((progressCtx->line_offset - 2) * (font_height + (font_height / 4))) + 8, FB_WIDTH, (font_height + (font_height / 4)) * 2, BG_COLOR_RGB, BG_COLOR_RGB, BG_COLOR_RGB);
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Output file: \"%s\".", strrchr(output_path, '/') + 1);
uiDrawString(strbuf, 8, ((progressCtx->line_offset - 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 255, 255);
uiRefreshDisplay();
if (DUMP_BUFFER_SIZE > (entry->dataSize - off)) n = (entry->dataSize - off);
breaks = (progressCtx->line_offset + 2);
if (!usePatch)
{ {
write_res = fwrite(buf, 1, old_file_chunk_size, outFile); proceed = processNcaCtrSectionBlock(&(romFsContext.ncmStorage), &(romFsContext.ncaId), &(romFsContext.aes_ctx), romFsContext.romfs_filedata_offset + entry->dataOff + off, buf, n, false);
if (write_res != old_file_chunk_size) } else {
{ proceed = readBktrSectionBlock(bktrContext.romfs_filedata_offset + entry->dataOff + off, buf, n);
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Failed to write %lu bytes chunk from offset 0x%016lX to part #%02u! (wrote %lu bytes)", old_file_chunk_size, off, splitIndex, write_res);
uiDrawString(strbuf, 8, ((progressCtx->line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0);
break;
}
} }
fclose(outFile); breaks = (progressCtx->line_offset - 4);
outFile = NULL;
if (new_file_chunk_size > 0 || (off + n) < entry->dataSize) if (!proceed) break;
if (entry->dataSize > FAT32_FILESIZE_LIMIT && doSplitting && (off + n) >= ((splitIndex + 1) * SPLIT_FILE_GENERIC_PART_SIZE))
{ {
char *tmp = strrchr(output_path, '.'); u64 new_file_chunk_size = ((off + n) - ((splitIndex + 1) * SPLIT_FILE_GENERIC_PART_SIZE));
if (tmp != NULL) *tmp = '\0'; u64 old_file_chunk_size = (n - new_file_chunk_size);
splitIndex++; if (old_file_chunk_size > 0)
sprintf(tmp_idx, ".%02u", splitIndex);
strcat(output_path, tmp_idx);
outFile = fopen(output_path, "wb");
if (!outFile)
{ {
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Failed to open output file for part #%u!", splitIndex); write_res = fwrite(buf, 1, old_file_chunk_size, outFile);
uiDrawString(strbuf, 8, ((progressCtx->line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0); if (write_res != old_file_chunk_size)
break;
}
if (new_file_chunk_size > 0)
{
write_res = fwrite(buf + old_file_chunk_size, 1, new_file_chunk_size, outFile);
if (write_res != new_file_chunk_size)
{ {
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Failed to write %lu bytes chunk from offset 0x%016lX to part #%02u! (wrote %lu bytes)", new_file_chunk_size, off + old_file_chunk_size, splitIndex, write_res); snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Failed to write %lu bytes chunk from offset 0x%016lX to part #%02u! (wrote %lu bytes)", old_file_chunk_size, off, splitIndex, write_res);
uiDrawString(strbuf, 8, ((progressCtx->line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0); uiDrawString(strbuf, 8, ((progressCtx->line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0);
proceed = false;
break; break;
} }
} }
}
} else {
write_res = fwrite(buf, 1, n, outFile);
if (write_res != n)
{
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Failed to write %lu bytes chunk from offset 0x%016lX! (wrote %lu bytes)", n, off, write_res);
uiDrawString(strbuf, 8, ((progressCtx->line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0);
if ((off + n) > FAT32_FILESIZE_LIMIT) fclose(outFile);
outFile = NULL;
if (new_file_chunk_size > 0 || (off + n) < entry->dataSize)
{ {
uiDrawString("You're probably using a FAT32 partition. Make sure to enable file splitting.", 8, ((progressCtx->line_offset + 4) * (font_height + (font_height / 4))) + (font_height / 8), 255, 255, 255); char *tmp = strrchr(output_path, '.');
fat32_error = true; if (tmp != NULL) *tmp = '\0';
splitIndex++;
sprintf(tmp_idx, ".%02u", splitIndex);
strcat(output_path, tmp_idx);
outFile = fopen(output_path, "wb");
if (!outFile)
{
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Failed to open output file for part #%u!", splitIndex);
uiDrawString(strbuf, 8, ((progressCtx->line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0);
proceed = false;
break;
}
if (new_file_chunk_size > 0)
{
write_res = fwrite(buf + old_file_chunk_size, 1, new_file_chunk_size, outFile);
if (write_res != new_file_chunk_size)
{
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Failed to write %lu bytes chunk from offset 0x%016lX to part #%02u! (wrote %lu bytes)", new_file_chunk_size, off + old_file_chunk_size, splitIndex, write_res);
uiDrawString(strbuf, 8, ((progressCtx->line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0);
proceed = false;
break;
}
}
} }
} else {
write_res = fwrite(buf, 1, n, outFile);
if (write_res != n)
{
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Failed to write %lu bytes chunk from offset 0x%016lX! (wrote %lu bytes)", n, off, write_res);
uiDrawString(strbuf, 8, ((progressCtx->line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0);
break; if ((off + n) > FAT32_FILESIZE_LIMIT)
{
uiDrawString("You're probably using a FAT32 partition. Make sure to enable file splitting.", 8, ((progressCtx->line_offset + 4) * (font_height + (font_height / 4))) + (font_height / 8), 255, 255, 255);
fat32_error = true;
}
proceed = false;
break;
}
} }
}
printProgressBar(progressCtx, true, n); printProgressBar(progressCtx, true, n);
if ((off + n) < entry->dataSize && ((off / DUMP_BUFFER_SIZE) % 10) == 0) if ((off + n) < entry->dataSize || (progressCtx->curOffset + n) < progressCtx->totalSize)
{
hidScanInput();
u32 keysDown = hidKeysDown(CONTROLLER_P1_AUTO);
if (keysDown & KEY_B)
{ {
uiDrawString("Process canceled.", 8, ((progressCtx->line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0); if (cancelProcessCheck(progressCtx))
break; {
uiDrawString("Process canceled.", 8, ((progressCtx->line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0);
proceed = false;
break;
}
} }
} }
if (outFile)
{
fclose(outFile);
outFile = NULL;
}
if (!proceed || off < entry->dataSize) break;
// Support empty files
if (!entry->dataSize)
{
uiFill(0, ((progressCtx->line_offset - 2) * (font_height + (font_height / 4))) + 8, FB_WIDTH, (font_height + (font_height / 4)) * 2, BG_COLOR_RGB, BG_COLOR_RGB, BG_COLOR_RGB);
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Output file: \"%s\".", strrchr(output_path, '/') + 1);
uiDrawString(strbuf, 8, ((progressCtx->line_offset - 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 255, 255);
if (progressCtx->totalSize == entry->dataSize) progressCtx->progress = 100;
printProgressBar(progressCtx, false, 0);
}
romfs_file_offset = entry->sibling;
if (romfs_file_offset == ROMFS_ENTRY_EMPTY) success = true;
} }
if (off >= entry->dataSize) success = true; free(buf);
// Support empty files
if (!entry->dataSize)
{
uiFill(0, ((progressCtx->line_offset - 2) * (font_height + (font_height / 4))) + 8, FB_WIDTH, (font_height + (font_height / 4)) * 2, BG_COLOR_RGB, BG_COLOR_RGB, BG_COLOR_RGB);
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Output file: \"%s\".", strrchr(output_path, '/') + 1);
uiDrawString(strbuf, 8, ((progressCtx->line_offset - 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 255, 255);
if (progressCtx->totalSize == entry->dataSize) progressCtx->progress = 100;
printProgressBar(progressCtx, false, 0);
}
out:
if (buf) free(buf);
if (outFile) fclose(outFile);
if (!success) if (!success)
{ {
@ -4197,11 +4195,6 @@ out:
romfs_path[orig_romfs_path_len] = '\0'; romfs_path[orig_romfs_path_len] = '\0';
output_path[orig_output_path_len] = '\0'; output_path[orig_output_path_len] = '\0';
if (success)
{
if (entry->sibling != ROMFS_ENTRY_EMPTY) success = recursiveDumpRomFsFile(entry->sibling, romfs_path, output_path, progressCtx, usePatch, doSplitting);
}
return success; return success;
} }
@ -4371,7 +4364,7 @@ bool dumpRomFsSectionData(u32 titleIndex, bool usePatch, bool doSplitting)
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 0, 255, 0); uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 0, 255, 0);
} else { } else {
setProgressBarError(&progressCtx); setProgressBarError(&progressCtx);
removeDirectory(dumpPath); removeDirectoryWithVerbose(dumpPath, "Deleting output directory. Please wait...");
} }
out: out:
@ -4641,12 +4634,9 @@ bool dumpFileFromRomFsSection(u32 titleIndex, u32 file_offset, bool usePatch, bo
printProgressBar(&progressCtx, true, n); printProgressBar(&progressCtx, true, n);
if ((progressCtx.curOffset + n) < progressCtx.totalSize && ((progressCtx.curOffset / DUMP_BUFFER_SIZE) % 10) == 0) if ((progressCtx.curOffset + n) < progressCtx.totalSize)
{ {
hidScanInput(); if (cancelProcessCheck(&progressCtx))
u32 keysDown = hidKeysDown(CONTROLLER_P1_AUTO);
if (keysDown & KEY_B)
{ {
uiDrawString("Process canceled.", 8, ((progressCtx.line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0); uiDrawString("Process canceled.", 8, ((progressCtx.line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0);
break; break;
@ -4773,7 +4763,14 @@ bool dumpCurrentDirFromRomFsSection(u32 titleIndex, bool usePatch, bool doSplitt
goto out; goto out;
} }
if (strlen(curRomFsPath) > 1) snprintf(romFsPath, sizeof(romFsPath) / sizeof(romFsPath[0]), curRomFsPath); if (strlen(curRomFsPath) > 1)
{
// Copy the whole current path and remove the last element (current directory) from it
// It will be re-added later
snprintf(romFsPath, sizeof(romFsPath) / sizeof(romFsPath[0]), curRomFsPath);
char *slash = strrchr(romFsPath, '/');
if (slash) *slash = '\0';
}
// Prepare output dump path // Prepare output dump path
snprintf(dumpPath, sizeof(dumpPath) / sizeof(dumpPath[0]), "%s%s", ROMFS_DUMP_PATH, dumpName); snprintf(dumpPath, sizeof(dumpPath) / sizeof(dumpPath[0]), "%s%s", ROMFS_DUMP_PATH, dumpName);
@ -4842,7 +4839,7 @@ bool dumpCurrentDirFromRomFsSection(u32 titleIndex, bool usePatch, bool doSplitt
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 0, 255, 0); uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 0, 255, 0);
} else { } else {
setProgressBarError(&progressCtx); setProgressBarError(&progressCtx);
removeDirectory(dumpPath); removeDirectoryWithVerbose(dumpPath, "Deleting output directory. Please wait...");
} }
out: out:

View file

@ -13,13 +13,15 @@
#define SPLIT_FILE_XCI_PART_SIZE (u64)0xFFFF8000 // 4 GiB - 0x8000 (4294934528 bytes) (based on XCI-Cutter) #define SPLIT_FILE_XCI_PART_SIZE (u64)0xFFFF8000 // 4 GiB - 0x8000 (4294934528 bytes) (based on XCI-Cutter)
#define SPLIT_FILE_NSP_PART_SIZE (u64)0xFFFF0000 // 4 GiB - 0x10000 (4294901760 bytes) (based on splitNSP.py) #define SPLIT_FILE_NSP_PART_SIZE (u64)0xFFFF0000 // 4 GiB - 0x10000 (4294901760 bytes) (based on splitNSP.py)
#define SPLIT_FILE_GENERIC_PART_SIZE SPLIT_FILE_XCI_PART_SIZE #define SPLIT_FILE_GENERIC_PART_SIZE SPLIT_FILE_NSP_PART_SIZE
#define CERT_OFFSET 0x7000 #define CERT_OFFSET 0x7000
#define CERT_SIZE 0x200 #define CERT_SIZE 0x200
#define SMOOTHING_FACTOR (double)0.05 #define SMOOTHING_FACTOR (double)0.05
#define CANCEL_BTN_SEC_HOLD 2 // The cancel button must be held for at least CANCEL_BTN_SEC_HOLD seconds to cancel an ongoing operation
typedef enum { typedef enum {
BATCH_SOURCE_ALL = 0, BATCH_SOURCE_ALL = 0,
BATCH_SOURCE_SDCARD, BATCH_SOURCE_SDCARD,

View file

@ -95,7 +95,7 @@ Result esCountPersonalizedTicket(u32 *num_tickets)
return rc; return rc;
} }
Result esListCommonTicket(u32 *numRightsIdsWritten, NcmRightsId *outBuf, size_t bufSize) Result esListCommonTicket(u32 *numRightsIdsWritten, FsRightsId *outBuf, size_t bufSize)
{ {
IpcCommand c; IpcCommand c;
ipcInitialize(&c); ipcInitialize(&c);
@ -135,7 +135,7 @@ Result esListCommonTicket(u32 *numRightsIdsWritten, NcmRightsId *outBuf, size_t
return rc; return rc;
} }
Result esListPersonalizedTicket(u32 *numRightsIdsWritten, NcmRightsId *outBuf, size_t bufSize) Result esListPersonalizedTicket(u32 *numRightsIdsWritten, FsRightsId *outBuf, size_t bufSize)
{ {
IpcCommand c; IpcCommand c;
ipcInitialize(&c); ipcInitialize(&c);

View file

@ -10,7 +10,7 @@ void esExit();
Result esCountCommonTicket(u32 *num_tickets); Result esCountCommonTicket(u32 *num_tickets);
Result esCountPersonalizedTicket(u32 *num_tickets); Result esCountPersonalizedTicket(u32 *num_tickets);
Result esListCommonTicket(u32 *numRightsIdsWritten, NcmRightsId *outBuf, size_t bufSize); Result esListCommonTicket(u32 *numRightsIdsWritten, FsRightsId *outBuf, size_t bufSize);
Result esListPersonalizedTicket(u32 *numRightsIdsWritten, NcmRightsId *outBuf, size_t bufSize); Result esListPersonalizedTicket(u32 *numRightsIdsWritten, FsRightsId *outBuf, size_t bufSize);
#endif #endif

View file

@ -837,7 +837,7 @@ bool retrieveNcaTikTitleKey(nca_header_t *dec_nca_header, u8 *out_tik, u8 *out_e
Result result; Result result;
u32 common_count, personalized_count, ids_written; u32 common_count, personalized_count, ids_written;
NcmRightsId *common_rights_ids = NULL, *personalized_rights_ids = NULL; FsRightsId *common_rights_ids = NULL, *personalized_rights_ids = NULL;
bool foundRightsId = false; bool foundRightsId = false;
u8 rightsIdType = 0; // 1 = Common, 2 = Personalized u8 rightsIdType = 0; // 1 = Common, 2 = Personalized
@ -894,7 +894,7 @@ bool retrieveNcaTikTitleKey(nca_header_t *dec_nca_header, u8 *out_tik, u8 *out_e
if (common_count) if (common_count)
{ {
common_rights_ids = calloc(common_count, sizeof(NcmRightsId)); common_rights_ids = calloc(common_count, sizeof(FsRightsId));
if (!common_rights_ids) if (!common_rights_ids)
{ {
uiDrawString("Error: failed to allocate memory for common tickets' rights IDs!", 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0); uiDrawString("Error: failed to allocate memory for common tickets' rights IDs!", 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0);
@ -902,7 +902,7 @@ bool retrieveNcaTikTitleKey(nca_header_t *dec_nca_header, u8 *out_tik, u8 *out_e
return false; return false;
} }
if (R_FAILED(result = esListCommonTicket(&ids_written, common_rights_ids, common_count * sizeof(NcmRightsId)))) if (R_FAILED(result = esListCommonTicket(&ids_written, common_rights_ids, common_count * sizeof(FsRightsId))))
{ {
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Error: esListCommonTicket failed! (0x%08X)", result); snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Error: esListCommonTicket failed! (0x%08X)", result);
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0); uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0);
@ -926,7 +926,7 @@ bool retrieveNcaTikTitleKey(nca_header_t *dec_nca_header, u8 *out_tik, u8 *out_e
if (!foundRightsId && personalized_count) if (!foundRightsId && personalized_count)
{ {
personalized_rights_ids = calloc(personalized_count, sizeof(NcmRightsId)); personalized_rights_ids = calloc(personalized_count, sizeof(FsRightsId));
if (!personalized_rights_ids) if (!personalized_rights_ids)
{ {
uiDrawString("Error: failed to allocate memory for personalized tickets' rights IDs!", 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0); uiDrawString("Error: failed to allocate memory for personalized tickets' rights IDs!", 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0);
@ -934,7 +934,7 @@ bool retrieveNcaTikTitleKey(nca_header_t *dec_nca_header, u8 *out_tik, u8 *out_e
return false; return false;
} }
if (R_FAILED(result = esListPersonalizedTicket(&ids_written, personalized_rights_ids, personalized_count * sizeof(NcmRightsId)))) if (R_FAILED(result = esListPersonalizedTicket(&ids_written, personalized_rights_ids, personalized_count * sizeof(FsRightsId))))
{ {
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Error: esListPersonalizedTicket failed! (0x%08X)", result); snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Error: esListPersonalizedTicket failed! (0x%08X)", result);
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0); uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0);
@ -1005,7 +1005,7 @@ bool retrieveNcaTikTitleKey(nca_header_t *dec_nca_header, u8 *out_tik, u8 *out_e
if (!testKeyPair(E, D, N)) return false; if (!testKeyPair(E, D, N)) return false;
if (R_FAILED(result = fsOpenBisStorage(&fatFsStorage, BIS_SYSTEM_PARTITION))) if (R_FAILED(result = fsOpenBisStorage(&fatFsStorage, FsBisStorageId_System)))
{ {
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Error: failed to open BIS System partition! (0x%08X)", result); snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Error: failed to open BIS System partition! (0x%08X)", result);
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0); uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0);

View file

@ -22,8 +22,6 @@
#define SIGTYPE_RSA2048_SHA1 (u32)0x10001 #define SIGTYPE_RSA2048_SHA1 (u32)0x10001
#define SIGTYPE_RSA2048_SHA256 (u32)0x10004 #define SIGTYPE_RSA2048_SHA256 (u32)0x10004
#define BIS_SYSTEM_PARTITION 31
#define COMMON_ETICKET_FILENAME "80000000000000e1" #define COMMON_ETICKET_FILENAME "80000000000000e1"
#define PERSONALIZED_ETICKET_FILENAME "80000000000000e2" #define PERSONALIZED_ETICKET_FILENAME "80000000000000e2"

View file

@ -493,9 +493,6 @@ void uiDrawString(const char *string, int x, int y, u8 r, u8 g, u8 b)
u32 tmpx = (x <= 8 ? 8 : (x + 8)); u32 tmpx = (x <= 8 ? 8 : (x + 8));
u32 tmpy = (font_height + (y <= 8 ? 8 : (y + 8))); u32 tmpy = (font_height + (y <= 8 ? 8 : (y + 8)));
FT_Error ret = 0; FT_Error ret = 0;
FT_UInt glyph_index;
FT_GlyphSlot standardFontSlot = standardFontFace->glyph;
FT_GlyphSlot nintendoExtFontSlot = nintendoExtFontFace->glyph;
u32 i; u32 i;
u32 str_size = strlen(string); u32 str_size = strlen(string);
@ -549,43 +546,39 @@ void uiDrawString(const char *string, int x, int y, u8 r, u8 g, u8 b)
if (useNintendoExt) if (useNintendoExt)
{ {
glyph_index = FT_Get_Char_Index(nintendoExtFontFace, tmpchar); ret = FT_Load_Char(nintendoExtFontFace, tmpchar, FT_LOAD_DEFAULT);
ret = FT_Load_Glyph(nintendoExtFontFace, glyph_index, FT_LOAD_DEFAULT);
if (ret == 0) ret = FT_Render_Glyph(nintendoExtFontFace->glyph, FT_RENDER_MODE_NORMAL); if (ret == 0) ret = FT_Render_Glyph(nintendoExtFontFace->glyph, FT_RENDER_MODE_NORMAL);
if (ret) break; if (ret) break;
if ((tmpx + (nintendoExtFontSlot->advance.x >> 6)) >= (FB_WIDTH - 8)) if ((tmpx + (nintendoExtFontFace->glyph->advance.x >> 6)) >= (FB_WIDTH - 8))
{ {
tmpx = 8; tmpx = 8;
tmpy += ((font_height + (font_height / 4)) + (font_height / 8)); tmpy += ((font_height + (font_height / 4)) + (font_height / 8));
breaks++; breaks++;
} }
uiDrawChar(&nintendoExtFontSlot->bitmap, tmpx + nintendoExtFontSlot->bitmap_left, tmpy - nintendoExtFontSlot->bitmap_top, r, g, b); uiDrawChar(&nintendoExtFontFace->glyph->bitmap, tmpx + nintendoExtFontFace->glyph->bitmap_left, tmpy - nintendoExtFontFace->glyph->bitmap_top, r, g, b);
tmpx += (nintendoExtFontSlot->advance.x >> 6); tmpx += (nintendoExtFontFace->glyph->advance.x >> 6);
tmpy += (nintendoExtFontSlot->advance.y >> 6); tmpy += (nintendoExtFontFace->glyph->advance.y >> 6);
} else { } else {
glyph_index = FT_Get_Char_Index(standardFontFace, tmpchar); ret = FT_Load_Char(standardFontFace, tmpchar, FT_LOAD_DEFAULT);
ret = FT_Load_Glyph(standardFontFace, glyph_index, FT_LOAD_DEFAULT);
if (ret == 0) ret = FT_Render_Glyph(standardFontFace->glyph, FT_RENDER_MODE_NORMAL); if (ret == 0) ret = FT_Render_Glyph(standardFontFace->glyph, FT_RENDER_MODE_NORMAL);
if (ret) break; if (ret) break;
if ((tmpx + (standardFontSlot->advance.x >> 6)) >= (FB_WIDTH - 8)) if ((tmpx + (standardFontFace->glyph->advance.x >> 6)) >= (FB_WIDTH - 8))
{ {
tmpx = 8; tmpx = 8;
tmpy += ((font_height + (font_height / 4)) + (font_height / 8)); tmpy += ((font_height + (font_height / 4)) + (font_height / 8));
breaks++; breaks++;
} }
uiDrawChar(&standardFontSlot->bitmap, tmpx + standardFontSlot->bitmap_left, tmpy - standardFontSlot->bitmap_top, r, g, b); uiDrawChar(&standardFontFace->glyph->bitmap, tmpx + standardFontFace->glyph->bitmap_left, tmpy - standardFontFace->glyph->bitmap_top, r, g, b);
tmpx += (standardFontSlot->advance.x >> 6); tmpx += (standardFontFace->glyph->advance.x >> 6);
tmpy += (standardFontSlot->advance.y >> 6); tmpy += (standardFontFace->glyph->advance.y >> 6);
} }
} }
} }
@ -595,9 +588,6 @@ u32 uiGetStrWidth(const char *string)
if (!string || !strlen(string)) return 0; if (!string || !strlen(string)) return 0;
FT_Error ret = 0; FT_Error ret = 0;
FT_UInt glyph_index;
FT_GlyphSlot standardFontSlot = standardFontFace->glyph;
FT_GlyphSlot nintendoExtFontSlot = nintendoExtFontFace->glyph;
u32 i; u32 i;
u32 str_size = strlen(string); u32 str_size = strlen(string);
@ -631,23 +621,19 @@ u32 uiGetStrWidth(const char *string)
if (useNintendoExt) if (useNintendoExt)
{ {
glyph_index = FT_Get_Char_Index(nintendoExtFontFace, tmpchar); ret = FT_Load_Char(nintendoExtFontFace, tmpchar, FT_LOAD_DEFAULT);
ret = FT_Load_Glyph(nintendoExtFontFace, glyph_index, FT_LOAD_DEFAULT);
if (ret == 0) ret = FT_Render_Glyph(nintendoExtFontFace->glyph, FT_RENDER_MODE_NORMAL); if (ret == 0) ret = FT_Render_Glyph(nintendoExtFontFace->glyph, FT_RENDER_MODE_NORMAL);
if (ret) break; if (ret) break;
width += (nintendoExtFontSlot->advance.x >> 6); width += (nintendoExtFontFace->glyph->advance.x >> 6);
} else { } else {
glyph_index = FT_Get_Char_Index(standardFontFace, tmpchar); ret = FT_Load_Char(standardFontFace, tmpchar, FT_LOAD_DEFAULT);
ret = FT_Load_Glyph(standardFontFace, glyph_index, FT_LOAD_DEFAULT);
if (ret == 0) ret = FT_Render_Glyph(standardFontFace->glyph, FT_RENDER_MODE_NORMAL); if (ret == 0) ret = FT_Render_Glyph(standardFontFace->glyph, FT_RENDER_MODE_NORMAL);
if (ret) break; if (ret) break;
width += (standardFontSlot->advance.x >> 6); width += (standardFontFace->glyph->advance.x >> 6);
} }
} }

View file

@ -2908,7 +2908,7 @@ void printProgressBar(progress_ctx_t *progressCtx, bool calcData, u64 chunkSize)
uiDrawString(strbuf, font_height * 2, (progressCtx->line_offset * (font_height + (font_height / 4))) + (font_height / 8), 255, 255, 255); uiDrawString(strbuf, font_height * 2, (progressCtx->line_offset * (font_height + (font_height / 4))) + (font_height / 8), 255, 255, 255);
uiFill(FB_WIDTH / 4, (progressCtx->line_offset * (font_height + (font_height / 4))) + 10, FB_WIDTH / 2, (font_height + (font_height / 4)), 0, 0, 0); uiFill(FB_WIDTH / 4, (progressCtx->line_offset * (font_height + (font_height / 4))) + 10, FB_WIDTH / 2, (font_height + (font_height / 4)), 0, 0, 0);
uiFill(FB_WIDTH / 4, (progressCtx->line_offset * (font_height + (font_height / 4))) + 10, (((u32)progressCtx->progress * ((u32)FB_WIDTH / 2)) / 100), (font_height + (font_height / 4)), 0, 255, 0); uiFill(FB_WIDTH / 4, (progressCtx->line_offset * (font_height + (font_height / 4))) + 10, (((progressCtx->curOffset + chunkSize) * (u64)(FB_WIDTH / 2)) / progressCtx->totalSize), (font_height + (font_height / 4)), 0, 255, 0);
uiFill(FB_WIDTH - (FB_WIDTH / 4), (progressCtx->line_offset * (font_height + (font_height / 4))) + 8, FB_WIDTH / 4, (font_height + (font_height / 4)), BG_COLOR_RGB, BG_COLOR_RGB, BG_COLOR_RGB); uiFill(FB_WIDTH - (FB_WIDTH / 4), (progressCtx->line_offset * (font_height + (font_height / 4))) + 8, FB_WIDTH / 4, (font_height + (font_height / 4)), BG_COLOR_RGB, BG_COLOR_RGB, BG_COLOR_RGB);
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "%u%% [%s / %s]", progressCtx->progress, progressCtx->curOffsetStr, progressCtx->totalSizeStr); snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "%u%% [%s / %s]", progressCtx->progress, progressCtx->curOffsetStr, progressCtx->totalSizeStr);
@ -2925,6 +2925,35 @@ void setProgressBarError(progress_ctx_t *progressCtx)
uiFill(FB_WIDTH / 4, (progressCtx->line_offset * (font_height + (font_height / 4))) + 10, (((u32)progressCtx->progress * ((u32)FB_WIDTH / 2)) / 100), (font_height + (font_height / 4)), 255, 0, 0); uiFill(FB_WIDTH / 4, (progressCtx->line_offset * (font_height + (font_height / 4))) + 10, (((u32)progressCtx->progress * ((u32)FB_WIDTH / 2)) / 100), (font_height + (font_height / 4)), 255, 0, 0);
} }
bool cancelProcessCheck(progress_ctx_t *progressCtx)
{
if (!progressCtx) return false;
hidScanInput();
progressCtx->cancelBtnState = (hidKeysHeld(CONTROLLER_P1_AUTO) & KEY_B);
if (progressCtx->cancelBtnState && progressCtx->cancelBtnState != progressCtx->cancelBtnStatePrev)
{
// Cancel button has just been pressed
timeGetCurrentTime(TimeType_LocalSystemClock, &(progressCtx->cancelStartTmr));
} else
if (progressCtx->cancelBtnState && progressCtx->cancelBtnState == progressCtx->cancelBtnStatePrev && progressCtx->cancelStartTmr)
{
// If the cancel button has been held up to this point, check if at least CANCEL_BTN_SEC_HOLD seconds have passed
// Only perform this check if cancelStartTmr has already been set to a value greater than zero
timeGetCurrentTime(TimeType_LocalSystemClock, &(progressCtx->cancelEndTmr));
if ((progressCtx->cancelEndTmr - progressCtx->cancelStartTmr) >= CANCEL_BTN_SEC_HOLD) return true;
} else {
progressCtx->cancelStartTmr = progressCtx->cancelEndTmr = 0;
}
progressCtx->cancelBtnStatePrev = progressCtx->cancelBtnState;
return false;
}
void convertDataToHexString(const u8 *data, const u32 dataSize, char *outBuf, const u32 outBufSize) void convertDataToHexString(const u8 *data, const u32 dataSize, char *outBuf, const u32 outBufSize)
{ {
if (!data || !dataSize || !outBuf || !outBufSize || outBufSize < ((dataSize * 2) + 1)) return; if (!data || !dataSize || !outBuf || !outBufSize || outBufSize < ((dataSize * 2) + 1)) return;
@ -3148,34 +3177,21 @@ bool checkIfDumpedNspContainsConsoleData(const char *nspPath)
return false; return false;
} }
void removeDirectory(const char *path) void removeDirectoryWithVerbose(const char *path, const char *msg)
{ {
if (!path || !strlen(path)) return; if (!path || !strlen(path) || !msg || !strlen(msg)) return;
struct dirent *ent; breaks += 2;
char cur_path[NAME_BUF_LEN] = {'\0'};
DIR *dir = opendir(path); uiDrawString(msg, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 255, 255, 255);
if (dir) uiRefreshDisplay();
{
while((ent = readdir(dir)) != NULL)
{
if ((strlen(ent->d_name) == 1 && !strcmp(ent->d_name, ".")) || (strlen(ent->d_name) == 2 && !strcmp(ent->d_name, ".."))) continue;
snprintf(cur_path, sizeof(cur_path) / sizeof(cur_path[0]), "%s/%s", path, ent->d_name); fsdevDeleteDirectoryRecursively(path);
if (ent->d_type == DT_DIR) uiFill(0, (breaks * (font_height + (font_height / 4))) + 8, FB_WIDTH, (font_height + (font_height / 2)), BG_COLOR_RGB, BG_COLOR_RGB, BG_COLOR_RGB);
{ uiRefreshDisplay();
removeDirectory(cur_path);
} else {
unlink(cur_path);
}
}
closedir(dir); breaks -= 2;
rmdir(path);
}
} }
bool parseNSWDBRelease(xmlDocPtr doc, xmlNodePtr cur, u64 gc_tid, u32 crc) bool parseNSWDBRelease(xmlDocPtr doc, xmlNodePtr cur, u64 gc_tid, u32 crc)

View file

@ -18,7 +18,7 @@
#define MiB (1024.0 * KiB) #define MiB (1024.0 * KiB)
#define GiB (1024.0 * MiB) #define GiB (1024.0 * MiB)
#define NAME_BUF_LEN 4096 #define NAME_BUF_LEN 1024
#define SOCK_BUFFERSIZE 65536 #define SOCK_BUFFERSIZE 65536
@ -128,6 +128,10 @@ typedef struct {
char etaInfo[32]; char etaInfo[32];
double lastSpeed; double lastSpeed;
double averageSpeed; double averageSpeed;
u32 cancelBtnState;
u32 cancelBtnStatePrev;
u64 cancelStartTmr;
u64 cancelEndTmr;
} PACKED progress_ctx_t; } PACKED progress_ctx_t;
typedef struct { typedef struct {
@ -227,6 +231,8 @@ void printProgressBar(progress_ctx_t *progressCtx, bool calcData, u64 chunkSize)
void setProgressBarError(progress_ctx_t *progressCtx); void setProgressBarError(progress_ctx_t *progressCtx);
bool cancelProcessCheck(progress_ctx_t *progressCtx);
void convertDataToHexString(const u8 *data, const u32 dataSize, char *outBuf, const u32 outBufSize); void convertDataToHexString(const u8 *data, const u32 dataSize, char *outBuf, const u32 outBufSize);
bool checkIfFileExists(const char *path); bool checkIfFileExists(const char *path);
@ -237,7 +243,7 @@ bool checkIfDumpedXciContainsCertificate(const char *xciPath);
bool checkIfDumpedNspContainsConsoleData(const char *nspPath); bool checkIfDumpedNspContainsConsoleData(const char *nspPath);
void removeDirectory(const char *path); void removeDirectoryWithVerbose(const char *path, const char *msg);
void gameCardDumpNSWDBCheck(u32 crc); void gameCardDumpNSWDBCheck(u32 crc);