From ed45a863faa0524d9701dc6a87bc1f51209430eb Mon Sep 17 00:00:00 2001 From: Pablo Curiel Date: Thu, 15 Aug 2019 01:21:51 -0400 Subject: [PATCH] Update to v1.1.4. --- Makefile | 2 +- README.md | 38 +++-- source/dumper.c | 389 ++++++++++++++++++++++++------------------------ source/dumper.h | 4 +- source/es.c | 4 +- source/es.h | 4 +- source/keys.c | 12 +- source/keys.h | 2 - source/ui.c | 42 ++---- source/util.c | 68 +++++---- source/util.h | 10 +- 11 files changed, 295 insertions(+), 280 deletions(-) diff --git a/Makefile b/Makefile index aac5d7d..49cb6af 100644 --- a/Makefile +++ b/Makefile @@ -33,7 +33,7 @@ include $(DEVKITPRO)/libnx/switch_rules VERSION_MAJOR := 1 VERSION_MINOR := 1 -VERSION_MICRO := 3 +VERSION_MICRO := 4 APP_TITLE := nxdumptool APP_AUTHOR := MCMrARM, DarkMatterCore diff --git a/README.md b/README.md index b930c43..3c13ea6 100644 --- a/README.md +++ b/README.md @@ -4,24 +4,25 @@ Nintendo Switch Dump Tool 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. * 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. * CRC32 checksum calculation for XCI/NSP dumps. * Full XCI dump verification using XML database from NSWDB.COM (NSWreleases.xml). -* XML database and in-app update via libcurl. -* Precise HFS0 raw partition dumping, using the root HFS0 header from the game card. -* HFS0 partition file data dumping. -* HFS0 partition file browser with manual file dump support. -* Program NCA ExeFS section file data dumping. -* Program NCA ExeFS section file browser with manual file dump support. -* Program NCA RomFS section file data dumping. -* Program NCA RomFS section file browser with manual file dump support. -* Manual game card certificate dump. +* XML database and in-app update capabilities via libcurl. +* Precise HFS0 raw partition dumping, using the root HFS0 header from the gamecard. +* HFS0 partition file data dumping + browser with manual file dump support. +* Program NCA ExeFS/RomFS section file data dumping + browser with manual file dump support. + * Compatible with both base applications and updates (if available). + * Supports manual RomFS directory dumping. +* Manual gamecard certificate dump. * Free SD card space checks in place. * 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. 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 -------------- +**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:** * General changes to the NSP dumping procedure: * 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:** -* Fixed game card 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. -* 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. +* 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 gamecards. +* 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. * Output naming scheme changed. Characters out of the ASCII range are replaced with underscores: - XCI dump: "sdmc:/[GameName] v[GameVersion] ([TitleID]).xci". diff --git a/source/dumper.c b/source/dumper.c index a7eb39d..095a485 100644 --- a/source/dumper.c +++ b/source/dumper.c @@ -106,6 +106,8 @@ bool dumpCartridgeImage(bool isFat32, bool setXciArchiveBit, bool dumpCert, bool size_t write_res; + u64 part_size = (!setXciArchiveBit ? SPLIT_FILE_XCI_PART_SIZE : SPLIT_FILE_NSP_PART_SIZE); + char *dumpName = generateFullDumpName(); 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 // Better safe than sorry unlink(filename); - removeDirectory(filename); + fsdevDeleteDirectoryRecursively(filename); 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); if (old_file_chunk_size > 0) @@ -426,12 +428,9 @@ bool dumpCartridgeImage(bool isFat32, bool setXciArchiveBit, bool dumpCert, bool printProgressBar(&progressCtx, true, n); - if ((progressCtx.curOffset + n) < progressCtx.totalSize && ((progressCtx.curOffset / DUMP_BUFFER_SIZE) % 10) == 0) + if ((progressCtx.curOffset + n) < progressCtx.totalSize) { - hidScanInput(); - - u32 keysDown = hidKeysDown(CONTROLLER_P1_AUTO); - if (keysDown & KEY_B) + if (cancelProcessCheck(&progressCtx)) { uiDrawString("Process canceled.", 8, ((progressCtx.line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0); proceed = false; @@ -546,7 +545,7 @@ bool dumpCartridgeImage(bool isFat32, bool setXciArchiveBit, bool dumpCert, bool if (setXciArchiveBit) { snprintf(filename, sizeof(filename) / sizeof(filename[0]), "%s%s.xci", XCI_DUMP_PATH, dumpName); - removeDirectory(filename); + fsdevDeleteDirectoryRecursively(filename); } else { 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 // Better safe than sorry unlink(dumpPath); - removeDirectory(dumpPath); + fsdevDeleteDirectoryRecursively(dumpPath); if (progressCtx.totalSize > FAT32_FILESIZE_LIMIT && isFat32) { @@ -1556,12 +1555,9 @@ bool dumpNintendoSubmissionPackage(nspDumpType selectedNspDumpType, u32 titleInd printProgressBar(&progressCtx, true, n); - if ((progressCtx.curOffset + n) < progressCtx.totalSize && ((progressCtx.curOffset / DUMP_BUFFER_SIZE) % 10) == 0) + if ((progressCtx.curOffset + n) < progressCtx.totalSize) { - hidScanInput(); - - u32 keysDown = hidKeysDown(CONTROLLER_P1_AUTO); - if (keysDown & KEY_B) + if (cancelProcessCheck(&progressCtx)) { uiDrawString("Process canceled.", 8, ((progressCtx.line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0); proceed = false; @@ -1919,12 +1915,9 @@ bool dumpNintendoSubmissionPackage(nspDumpType selectedNspDumpType, u32 titleInd printProgressBar(&progressCtx, true, n); - if ((progressCtx.curOffset + n) < progressCtx.totalSize && ((progressCtx.curOffset / DUMP_BUFFER_SIZE) % 10) == 0) + if ((progressCtx.curOffset + n) < progressCtx.totalSize) { - hidScanInput(); - - u32 keysDown = hidKeysDown(CONTROLLER_P1_AUTO); - if (keysDown & KEY_B) + if (cancelProcessCheck(&progressCtx)) { uiDrawString("Process canceled.", 8, ((progressCtx.line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0); proceed = false; @@ -2101,12 +2094,9 @@ bool dumpNintendoSubmissionPackage(nspDumpType selectedNspDumpType, u32 titleInd printProgressBar(&progressCtx, true, n); - if ((progressCtx.curOffset + n) < progressCtx.totalSize && ((progressCtx.curOffset / DUMP_BUFFER_SIZE) % 10) == 0) + if ((progressCtx.curOffset + n) < progressCtx.totalSize) { - hidScanInput(); - - u32 keysDown = hidKeysDown(CONTROLLER_P1_AUTO); - if (keysDown & KEY_B) + if (cancelProcessCheck(&progressCtx)) { uiDrawString("Process canceled.", 8, ((progressCtx.line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0); proceed = false; @@ -2168,7 +2158,7 @@ out: if (progressCtx.totalSize > FAT32_FILESIZE_LIMIT && isFat32) { - removeDirectory(dumpPath); + fsdevDeleteDirectoryRecursively(dumpPath); } else { unlink(dumpPath); } @@ -2832,12 +2822,9 @@ bool dumpRawHfs0Partition(u32 partition, bool doSplitting) printProgressBar(&progressCtx, true, n); - if ((progressCtx.curOffset + n) < progressCtx.totalSize && ((progressCtx.curOffset / DUMP_BUFFER_SIZE) % 10) == 0) + if ((progressCtx.curOffset + n) < progressCtx.totalSize) { - hidScanInput(); - - u32 keysDown = hidKeysDown(CONTROLLER_P1_AUTO); - if (keysDown & KEY_B) + if (cancelProcessCheck(&progressCtx)) { uiDrawString("Process canceled.", 8, ((progressCtx.line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0); break; @@ -3048,12 +3035,9 @@ bool copyFileFromHfs0(u32 partition, const char* source, const char* dest, const printProgressBar(progressCtx, true, n); - if ((off + n) < size && ((off / DUMP_BUFFER_SIZE) % 10) == 0) + if ((off + n) < size || (progressCtx->curOffset + n) < progressCtx->totalSize) { - hidScanInput(); - - u32 keysDown = hidKeysDown(CONTROLLER_P1_AUTO); - if (keysDown & KEY_B) + if (cancelProcessCheck(progressCtx)) { uiDrawString("Process canceled.", 8, ((progressCtx->line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0); 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); uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 0, 255, 0); } else { - removeDirectory(dumpPath); + removeDirectoryWithVerbose(dumpPath, "Deleting output directory. Please wait..."); } } 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); @@ -3629,12 +3613,9 @@ bool dumpExeFsSectionData(u32 titleIndex, bool usePatch, bool doSplitting) printProgressBar(&progressCtx, true, n); - if ((progressCtx.curOffset + n) < progressCtx.totalSize && ((progressCtx.curOffset / DUMP_BUFFER_SIZE) % 10) == 0) + if ((progressCtx.curOffset + n) < progressCtx.totalSize) { - hidScanInput(); - - u32 keysDown = hidKeysDown(CONTROLLER_P1_AUTO); - if (keysDown & KEY_B) + if (cancelProcessCheck(&progressCtx)) { uiDrawString("Process canceled.", 8, ((progressCtx.line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0); 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); } else { setProgressBarError(&progressCtx); - removeDirectory(dumpPath); if (fat32_error) breaks += 2; + removeDirectoryWithVerbose(dumpPath, "Deleting output directory. Please wait..."); } out: @@ -3916,12 +3897,9 @@ bool dumpFileFromExeFsSection(u32 titleIndex, u32 fileIndex, bool usePatch, bool printProgressBar(&progressCtx, true, n); - if ((progressCtx.curOffset + n) < progressCtx.totalSize && ((progressCtx.curOffset / DUMP_BUFFER_SIZE) % 10) == 0) + if ((progressCtx.curOffset + n) < progressCtx.totalSize) { - hidScanInput(); - - u32 keysDown = hidKeysDown(CONTROLLER_P1_AUTO); - if (keysDown & KEY_B) + if (cancelProcessCheck(&progressCtx)) { uiDrawString("Process canceled.", 8, ((progressCtx.line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0); break; @@ -4010,183 +3988,203 @@ bool recursiveDumpRomFsFile(u32 file_offset, char *romfs_path, char *output_path u8 splitIndex = 0; bool proceed = true, success = false, fat32_error = false; + u32 romfs_file_offset = file_offset; + romfs_file *entry = NULL; + u64 off = 0; size_t write_res; 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); 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); - 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); - uiDrawString(strbuf, 8, ((progressCtx->line_offset - 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 255, 255); + entry = (!usePatch ? (romfs_file*)((u8*)romFsContext.romfs_file_entries + romfs_file_offset) : (romfs_file*)((u8*)bktrContext.romfs_file_entries + romfs_file_offset)); - uiRefreshDisplay(); - - if (DUMP_BUFFER_SIZE > (entry->dataSize - off)) n = (entry->dataSize - off); - - breaks = (progressCtx->line_offset + 2); - - if (!usePatch) + // Check if we're dealing with a nameless file + if (!entry->nameLen) { - proceed = processNcaCtrSectionBlock(&(romFsContext.ncmStorage), &(romFsContext.ncaId), &(romFsContext.aes_ctx), romFsContext.romfs_filedata_offset + entry->dataOff + off, buf, n, false); - } else { - proceed = readBktrSectionBlock(bktrContext.romfs_filedata_offset + entry->dataOff + off, buf, n); + 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); + break; } - breaks = (progressCtx->line_offset - 4); - - if (!proceed) break; - - if (entry->dataSize > FAT32_FILESIZE_LIMIT && doSplitting && (off + n) >= ((splitIndex + 1) * SPLIT_FILE_GENERIC_PART_SIZE)) + if ((orig_romfs_path_len + 1 + entry->nameLen) >= (NAME_BUF_LEN * 2) || (orig_output_path_len + 1 + entry->nameLen) >= (NAME_BUF_LEN * 2)) { - u64 new_file_chunk_size = ((off + n) - ((splitIndex + 1) * SPLIT_FILE_GENERIC_PART_SIZE)); - u64 old_file_chunk_size = (n - new_file_chunk_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); + break; + } + + // 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); - if (old_file_chunk_size > 0) + 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); - if (write_res != old_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)", 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; - } + proceed = processNcaCtrSectionBlock(&(romFsContext.ncmStorage), &(romFsContext.ncaId), &(romFsContext.aes_ctx), romFsContext.romfs_filedata_offset + entry->dataOff + off, buf, n, false); + } else { + proceed = readBktrSectionBlock(bktrContext.romfs_filedata_offset + entry->dataOff + off, buf, n); } - fclose(outFile); - outFile = NULL; + breaks = (progressCtx->line_offset - 4); - 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, '.'); - if (tmp != NULL) *tmp = '\0'; + u64 new_file_chunk_size = ((off + n) - ((splitIndex + 1) * SPLIT_FILE_GENERIC_PART_SIZE)); + u64 old_file_chunk_size = (n - new_file_chunk_size); - splitIndex++; - sprintf(tmp_idx, ".%02u", splitIndex); - strcat(output_path, tmp_idx); - - outFile = fopen(output_path, "wb"); - if (!outFile) + if (old_file_chunk_size > 0) { - 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); - 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) + write_res = fwrite(buf, 1, old_file_chunk_size, outFile); + if (write_res != old_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); + 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); - 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); - fat32_error = true; + char *tmp = strrchr(output_path, '.'); + 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); + + 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; } - - break; } - } - - printProgressBar(progressCtx, true, n); - - if ((off + n) < entry->dataSize && ((off / DUMP_BUFFER_SIZE) % 10) == 0) - { - hidScanInput(); - u32 keysDown = hidKeysDown(CONTROLLER_P1_AUTO); - if (keysDown & KEY_B) + printProgressBar(progressCtx, true, n); + + if ((off + n) < entry->dataSize || (progressCtx->curOffset + n) < progressCtx->totalSize) { - uiDrawString("Process canceled.", 8, ((progressCtx->line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0); - break; + if (cancelProcessCheck(progressCtx)) + { + 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; - - // 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); + free(buf); if (!success) { @@ -4197,11 +4195,6 @@ out: romfs_path[orig_romfs_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; } @@ -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); } else { setProgressBarError(&progressCtx); - removeDirectory(dumpPath); + removeDirectoryWithVerbose(dumpPath, "Deleting output directory. Please wait..."); } out: @@ -4641,12 +4634,9 @@ bool dumpFileFromRomFsSection(u32 titleIndex, u32 file_offset, bool usePatch, bo printProgressBar(&progressCtx, true, n); - if ((progressCtx.curOffset + n) < progressCtx.totalSize && ((progressCtx.curOffset / DUMP_BUFFER_SIZE) % 10) == 0) + if ((progressCtx.curOffset + n) < progressCtx.totalSize) { - hidScanInput(); - - u32 keysDown = hidKeysDown(CONTROLLER_P1_AUTO); - if (keysDown & KEY_B) + if (cancelProcessCheck(&progressCtx)) { uiDrawString("Process canceled.", 8, ((progressCtx.line_offset + 2) * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0); break; @@ -4773,7 +4763,14 @@ bool dumpCurrentDirFromRomFsSection(u32 titleIndex, bool usePatch, bool doSplitt 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 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); } else { setProgressBarError(&progressCtx); - removeDirectory(dumpPath); + removeDirectoryWithVerbose(dumpPath, "Deleting output directory. Please wait..."); } out: diff --git a/source/dumper.h b/source/dumper.h index aec3492..0e66c25 100644 --- a/source/dumper.h +++ b/source/dumper.h @@ -13,13 +13,15 @@ #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_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_SIZE 0x200 #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 { BATCH_SOURCE_ALL = 0, BATCH_SOURCE_SDCARD, diff --git a/source/es.c b/source/es.c index 5504fcf..20f2f17 100644 --- a/source/es.c +++ b/source/es.c @@ -95,7 +95,7 @@ Result esCountPersonalizedTicket(u32 *num_tickets) return rc; } -Result esListCommonTicket(u32 *numRightsIdsWritten, NcmRightsId *outBuf, size_t bufSize) +Result esListCommonTicket(u32 *numRightsIdsWritten, FsRightsId *outBuf, size_t bufSize) { IpcCommand c; ipcInitialize(&c); @@ -135,7 +135,7 @@ Result esListCommonTicket(u32 *numRightsIdsWritten, NcmRightsId *outBuf, size_t return rc; } -Result esListPersonalizedTicket(u32 *numRightsIdsWritten, NcmRightsId *outBuf, size_t bufSize) +Result esListPersonalizedTicket(u32 *numRightsIdsWritten, FsRightsId *outBuf, size_t bufSize) { IpcCommand c; ipcInitialize(&c); diff --git a/source/es.h b/source/es.h index eb2e826..d09a83e 100644 --- a/source/es.h +++ b/source/es.h @@ -10,7 +10,7 @@ void esExit(); Result esCountCommonTicket(u32 *num_tickets); Result esCountPersonalizedTicket(u32 *num_tickets); -Result esListCommonTicket(u32 *numRightsIdsWritten, NcmRightsId *outBuf, size_t bufSize); -Result esListPersonalizedTicket(u32 *numRightsIdsWritten, NcmRightsId *outBuf, size_t bufSize); +Result esListCommonTicket(u32 *numRightsIdsWritten, FsRightsId *outBuf, size_t bufSize); +Result esListPersonalizedTicket(u32 *numRightsIdsWritten, FsRightsId *outBuf, size_t bufSize); #endif diff --git a/source/keys.c b/source/keys.c index 0151f59..f60dcfa 100644 --- a/source/keys.c +++ b/source/keys.c @@ -837,7 +837,7 @@ bool retrieveNcaTikTitleKey(nca_header_t *dec_nca_header, u8 *out_tik, u8 *out_e Result result; 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; 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) { - common_rights_ids = calloc(common_count, sizeof(NcmRightsId)); + common_rights_ids = calloc(common_count, sizeof(FsRightsId)); 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); @@ -902,7 +902,7 @@ bool retrieveNcaTikTitleKey(nca_header_t *dec_nca_header, u8 *out_tik, u8 *out_e 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); 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) { - personalized_rights_ids = calloc(personalized_count, sizeof(NcmRightsId)); + personalized_rights_ids = calloc(personalized_count, sizeof(FsRightsId)); 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); @@ -934,7 +934,7 @@ bool retrieveNcaTikTitleKey(nca_header_t *dec_nca_header, u8 *out_tik, u8 *out_e 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); 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 (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); uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0); diff --git a/source/keys.h b/source/keys.h index 8f6bb7c..6dd2bbb 100644 --- a/source/keys.h +++ b/source/keys.h @@ -22,8 +22,6 @@ #define SIGTYPE_RSA2048_SHA1 (u32)0x10001 #define SIGTYPE_RSA2048_SHA256 (u32)0x10004 -#define BIS_SYSTEM_PARTITION 31 - #define COMMON_ETICKET_FILENAME "80000000000000e1" #define PERSONALIZED_ETICKET_FILENAME "80000000000000e2" diff --git a/source/ui.c b/source/ui.c index b6e672a..4fd8fce 100644 --- a/source/ui.c +++ b/source/ui.c @@ -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 tmpy = (font_height + (y <= 8 ? 8 : (y + 8))); FT_Error ret = 0; - FT_UInt glyph_index; - FT_GlyphSlot standardFontSlot = standardFontFace->glyph; - FT_GlyphSlot nintendoExtFontSlot = nintendoExtFontFace->glyph; u32 i; 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) { - glyph_index = FT_Get_Char_Index(nintendoExtFontFace, tmpchar); - - ret = FT_Load_Glyph(nintendoExtFontFace, glyph_index, FT_LOAD_DEFAULT); + ret = FT_Load_Char(nintendoExtFontFace, tmpchar, FT_LOAD_DEFAULT); if (ret == 0) ret = FT_Render_Glyph(nintendoExtFontFace->glyph, FT_RENDER_MODE_NORMAL); if (ret) break; - if ((tmpx + (nintendoExtFontSlot->advance.x >> 6)) >= (FB_WIDTH - 8)) + if ((tmpx + (nintendoExtFontFace->glyph->advance.x >> 6)) >= (FB_WIDTH - 8)) { tmpx = 8; tmpy += ((font_height + (font_height / 4)) + (font_height / 8)); 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); - tmpy += (nintendoExtFontSlot->advance.y >> 6); + tmpx += (nintendoExtFontFace->glyph->advance.x >> 6); + tmpy += (nintendoExtFontFace->glyph->advance.y >> 6); } else { - glyph_index = FT_Get_Char_Index(standardFontFace, tmpchar); - - ret = FT_Load_Glyph(standardFontFace, glyph_index, FT_LOAD_DEFAULT); + ret = FT_Load_Char(standardFontFace, tmpchar, FT_LOAD_DEFAULT); if (ret == 0) ret = FT_Render_Glyph(standardFontFace->glyph, FT_RENDER_MODE_NORMAL); if (ret) break; - if ((tmpx + (standardFontSlot->advance.x >> 6)) >= (FB_WIDTH - 8)) + if ((tmpx + (standardFontFace->glyph->advance.x >> 6)) >= (FB_WIDTH - 8)) { tmpx = 8; tmpy += ((font_height + (font_height / 4)) + (font_height / 8)); 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); - tmpy += (standardFontSlot->advance.y >> 6); + tmpx += (standardFontFace->glyph->advance.x >> 6); + tmpy += (standardFontFace->glyph->advance.y >> 6); } } } @@ -595,9 +588,6 @@ u32 uiGetStrWidth(const char *string) if (!string || !strlen(string)) return 0; FT_Error ret = 0; - FT_UInt glyph_index; - FT_GlyphSlot standardFontSlot = standardFontFace->glyph; - FT_GlyphSlot nintendoExtFontSlot = nintendoExtFontFace->glyph; u32 i; u32 str_size = strlen(string); @@ -631,23 +621,19 @@ u32 uiGetStrWidth(const char *string) if (useNintendoExt) { - glyph_index = FT_Get_Char_Index(nintendoExtFontFace, tmpchar); - - ret = FT_Load_Glyph(nintendoExtFontFace, glyph_index, FT_LOAD_DEFAULT); + ret = FT_Load_Char(nintendoExtFontFace, tmpchar, FT_LOAD_DEFAULT); if (ret == 0) ret = FT_Render_Glyph(nintendoExtFontFace->glyph, FT_RENDER_MODE_NORMAL); if (ret) break; - width += (nintendoExtFontSlot->advance.x >> 6); + width += (nintendoExtFontFace->glyph->advance.x >> 6); } else { - glyph_index = FT_Get_Char_Index(standardFontFace, tmpchar); - - ret = FT_Load_Glyph(standardFontFace, glyph_index, FT_LOAD_DEFAULT); + ret = FT_Load_Char(standardFontFace, tmpchar, FT_LOAD_DEFAULT); if (ret == 0) ret = FT_Render_Glyph(standardFontFace->glyph, FT_RENDER_MODE_NORMAL); if (ret) break; - width += (standardFontSlot->advance.x >> 6); + width += (standardFontFace->glyph->advance.x >> 6); } } diff --git a/source/util.c b/source/util.c index 9a2ced7..7b74125 100644 --- a/source/util.c +++ b/source/util.c @@ -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); 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); 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); } +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) { if (!data || !dataSize || !outBuf || !outBufSize || outBufSize < ((dataSize * 2) + 1)) return; @@ -3148,34 +3177,21 @@ bool checkIfDumpedNspContainsConsoleData(const char *nspPath) 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; - char cur_path[NAME_BUF_LEN] = {'\0'}; + breaks += 2; - DIR *dir = opendir(path); - if (dir) - { - 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); - - if (ent->d_type == DT_DIR) - { - removeDirectory(cur_path); - } else { - unlink(cur_path); - } - } - - closedir(dir); - - rmdir(path); - } + uiDrawString(msg, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 255, 255, 255); + uiRefreshDisplay(); + + fsdevDeleteDirectoryRecursively(path); + + 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(); + + breaks -= 2; } bool parseNSWDBRelease(xmlDocPtr doc, xmlNodePtr cur, u64 gc_tid, u32 crc) diff --git a/source/util.h b/source/util.h index 7ba0525..632335b 100644 --- a/source/util.h +++ b/source/util.h @@ -18,7 +18,7 @@ #define MiB (1024.0 * KiB) #define GiB (1024.0 * MiB) -#define NAME_BUF_LEN 4096 +#define NAME_BUF_LEN 1024 #define SOCK_BUFFERSIZE 65536 @@ -128,6 +128,10 @@ typedef struct { char etaInfo[32]; double lastSpeed; double averageSpeed; + u32 cancelBtnState; + u32 cancelBtnStatePrev; + u64 cancelStartTmr; + u64 cancelEndTmr; } PACKED progress_ctx_t; typedef struct { @@ -227,6 +231,8 @@ void printProgressBar(progress_ctx_t *progressCtx, bool calcData, u64 chunkSize) 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); bool checkIfFileExists(const char *path); @@ -237,7 +243,7 @@ bool checkIfDumpedXciContainsCertificate(const char *xciPath); bool checkIfDumpedNspContainsConsoleData(const char *nspPath); -void removeDirectory(const char *path); +void removeDirectoryWithVerbose(const char *path, const char *msg); void gameCardDumpNSWDBCheck(u32 crc);