mirror of
https://github.com/DarkMatterCore/nxdumptool.git
synced 2024-11-22 18:26:39 +00:00
Update to v1.0.6.
This commit is contained in:
parent
edd7eee294
commit
d22add43bf
9 changed files with 651 additions and 769 deletions
27
README.md
27
README.md
|
@ -4,18 +4,18 @@ Nintendo Switch Game Card Dump Tool
|
|||
Main features
|
||||
--------------
|
||||
|
||||
* Generates XCI cartridge dumps (with optional certificate removal and optional trimming).
|
||||
* Generates XCI cartridge dumps with optional certificate removal and optional trimming.
|
||||
* CRC32 checksum calculation for XCI dumps.
|
||||
* Full XCI dump verification using XML database from nswdb.com (NSWreleases.xml).
|
||||
* XML database update via libcurl.
|
||||
* Precise HFS0 raw partition dumping (using the root HFS0 header from the game card).
|
||||
* 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.
|
||||
* Partition filesystem data dumping.
|
||||
* Partition filesystem browser (with manual file dump support).
|
||||
* Partition filesystem browser with manual file dump support.
|
||||
* Manual game card certificate dump.
|
||||
* Free SD card space checks in place.
|
||||
* File splitting support for all operations, using 2 GiB parts.
|
||||
* Game card Title ID and Control.nacp retrieval support using NCM and NS services.
|
||||
* Dump speed and ETA calculation.
|
||||
* Dump speed, ETA calculation and progress bar.
|
||||
|
||||
Thanks to
|
||||
--------------
|
||||
|
@ -31,6 +31,21 @@ Thanks to
|
|||
Changelog
|
||||
--------------
|
||||
|
||||
**v1.0.6:**
|
||||
|
||||
* Updated application codebase in order to make it compatible with the latest devkitA64 and libnx releases.
|
||||
* Removed some fs-srv service functions from fsext.c/h that have been included in libnx (and fixed the ones that haven't).
|
||||
* Revamped the GFX code to replace the 8x8 ASCII font with the shared system font, using the pl service and FreeType.
|
||||
* Enabled (and fixed) the in-app update option. HTTPS compatibility is achieved through the mbedtls portlib.
|
||||
* Disabled screen dimming and auto sleep.
|
||||
* Added file counter to partition browser.
|
||||
* Changed the naming convention for split gamecard dumps to *.xc[part number], in order to make them compatible with SX OS and other tools right away.
|
||||
* Increased the delay after inserting a new gamecard by 1 second.
|
||||
* Added a gamecard detection thread to monitor gamecard state changes in a better way. This thread is hooked to a gamecard detection kernel handle retrieved through an IEventNotifier object.
|
||||
* Replaced partition filesystem mounting through fs-srv service calls with manual HFS0 partition header parsing. This should fix issues when browsing the Logo partition from type 0x02 gamecards.
|
||||
* Blocked HOME button presses when running as a regular/system application instead of an applet. A warning message will be displayed whenever any operation is started if the application is running as an applet.
|
||||
* Added detection for bundled FW versions 6.0.0 - 8.0.0.
|
||||
|
||||
**v1.0.5:**
|
||||
|
||||
* Fixed game card version reading (now using the ncm service instead of retrieving it from the cached Control.nacp).
|
||||
|
|
1015
source/dumper.c
1015
source/dumper.c
File diff suppressed because it is too large
Load diff
|
@ -33,6 +33,8 @@
|
|||
#define GAMECARD_TYPE2_PART_NAMES(x) ((x) == 0 ? "Update" : ((x) == 1 ? "Logo" : ((x) == 2 ? "Normal" : ((x) == 3 ? "Secure" : "Unknown"))))
|
||||
#define GAMECARD_PARTITION_NAME(x, y) ((x) == GAMECARD_TYPE1_PARTITION_CNT ? GAMECARD_TYPE1_PART_NAMES(y) : ((x) == GAMECARD_TYPE2_PARTITION_CNT ? GAMECARD_TYPE2_PART_NAMES(y) : "Unknown"))
|
||||
|
||||
#define HFS0_TO_ISTORAGE_IDX(x, y) ((x) == GAMECARD_TYPE1_PARTITION_CNT ? ((y) < 2 ? 0 : 1) : ((y) < 3 ? 0 : 1))
|
||||
|
||||
#define GAMECARD_SIZE_1GiB (u64)0x40000000
|
||||
#define GAMECARD_SIZE_2GiB (u64)0x80000000
|
||||
#define GAMECARD_SIZE_4GiB (u64)0x100000000
|
||||
|
@ -81,18 +83,12 @@ typedef struct
|
|||
u8 hashed_region_sha256[0x20];
|
||||
} PACKED hfs0_entry_table;
|
||||
|
||||
void workaroundPartitionZeroAccess(FsDeviceOperator* fsOperator);
|
||||
bool getRootHfs0Header(FsDeviceOperator* fsOperator);
|
||||
bool getHsf0PartitionDetails(u32 partition, u64 *out_offset, u64 *out_size);
|
||||
bool dumpGameCartridge(FsDeviceOperator* fsOperator, bool isFat32, bool dumpCert, bool trimDump, bool calcCrc);
|
||||
bool dumpRawPartition(FsDeviceOperator* fsOperator, u32 partition, bool doSplitting);
|
||||
bool openPartitionFs(FsFileSystem* ret, FsDeviceOperator* fsOperator, u32 partition);
|
||||
bool copyFile(const char* source, const char* dest, bool doSplitting, bool calcEta);
|
||||
bool copyDirectory(const char* source, const char* dest, bool doSplitting);
|
||||
void removeDirectory(const char *path);
|
||||
bool getDirectorySize(const char *path, u64 *out_size);
|
||||
bool dumpPartitionData(FsDeviceOperator* fsOperator, u32 partition);
|
||||
bool mountViewPartition(FsDeviceOperator *fsOperator, FsFileSystem *out, u32 partition);
|
||||
bool getHfs0FileList(FsDeviceOperator* fsOperator, u32 partition);
|
||||
bool dumpFileFromPartition(FsDeviceOperator* fsOperator, u32 partition, u32 file, char *filename);
|
||||
bool dumpGameCertificate(FsDeviceOperator *fsOperator);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -46,47 +46,6 @@ Result fsOpenGameCardStorage(FsStorage* out, const FsGameCardHandle* handle, u32
|
|||
return rc;
|
||||
}
|
||||
|
||||
Result fsOpenGameCardFileSystem(FsFileSystem* out, const FsGameCardHandle* handle, u32 partition)
|
||||
{
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u32 handle;
|
||||
u32 partition;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(fsGetServiceSession(), &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 31;
|
||||
raw->handle = handle->value;
|
||||
raw->partition = partition;
|
||||
|
||||
Result rc = serviceIpcDispatch(fsGetServiceSession());
|
||||
|
||||
if (R_SUCCEEDED(rc))
|
||||
{
|
||||
IpcParsedCommand r;
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(fsGetServiceSession(), &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) serviceCreateSubservice(&out->s, fsGetServiceSession(), &r, 0);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result fsOpenGameCardDetectionEventNotifier(FsEventNotifier* out)
|
||||
{
|
||||
IpcCommand c;
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
// IFileSystemProxy
|
||||
Result fsOpenGameCardStorage(FsStorage* out, const FsGameCardHandle* handle, u32 partition);
|
||||
Result fsOpenGameCardFileSystem(FsFileSystem* out, const FsGameCardHandle* handle, u32 partition);
|
||||
Result fsOpenGameCardDetectionEventNotifier(FsEventNotifier* out);
|
||||
|
||||
// IDeviceOperator
|
||||
|
|
|
@ -57,7 +57,7 @@ int main(int argc, char *argv[])
|
|||
result = fsOpenGameCardDetectionEventNotifier(&fsGameCardEventNotifier);
|
||||
if (R_SUCCEEDED(result))
|
||||
{
|
||||
/* Retrieve kernel event handle */
|
||||
/* Retrieve gamecard detection event handle */
|
||||
result = fsEventNotifierGetEventHandle(&fsGameCardEventNotifier, &fsGameCardEventHandle);
|
||||
if (R_SUCCEEDED(result))
|
||||
{
|
||||
|
@ -161,7 +161,7 @@ int main(int argc, char *argv[])
|
|||
ret = -9;
|
||||
}
|
||||
|
||||
/* Close kernel event */
|
||||
/* Close gamecard detection kernel event */
|
||||
eventClose(&fsGameCardKernelEvent);
|
||||
} else {
|
||||
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Failed to retrieve gamecard detection event handle! (0x%08X)", result);
|
||||
|
@ -171,7 +171,7 @@ int main(int argc, char *argv[])
|
|||
ret = -8;
|
||||
}
|
||||
|
||||
/* Close gamecard event notifier */
|
||||
/* Close gamecard detection event notifier */
|
||||
fsEventNotifierClose(&fsGameCardEventNotifier);
|
||||
} else {
|
||||
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Failed to open gamecard detection event notifier! (0x%08X)", result);
|
||||
|
|
209
source/ui.c
209
source/ui.c
|
@ -19,6 +19,8 @@
|
|||
|
||||
extern FsDeviceOperator fsOperatorInstance;
|
||||
|
||||
extern AppletType programAppletType;
|
||||
|
||||
extern bool gameCardInserted;
|
||||
|
||||
extern char gameCardSizeStr[32], trimmedCardSizeStr[32];
|
||||
|
@ -27,14 +29,16 @@ extern char *hfs0_header;
|
|||
extern u64 hfs0_offset, hfs0_size;
|
||||
extern u32 hfs0_partition_cnt;
|
||||
|
||||
extern char *partitionHfs0Header;
|
||||
extern u64 partitionHfs0HeaderOffset, partitionHfs0HeaderSize;
|
||||
extern u32 partitionHfs0FileCount, partitionHfs0StrTableSize;
|
||||
|
||||
extern u64 gameCardTitleID;
|
||||
extern u32 gameCardVersion;
|
||||
extern char gameCardName[0x201], fixedGameCardName[0x201], gameCardAuthor[0x101], gameCardVersionStr[64];
|
||||
|
||||
extern char gameCardUpdateVersionStr[128];
|
||||
|
||||
extern char currentDirectory[NAME_BUF_LEN];
|
||||
|
||||
extern char *filenameBuffer;
|
||||
extern char *filenames[FILENAME_MAX_CNT];
|
||||
extern int filenamesCount;
|
||||
|
@ -54,19 +58,16 @@ int scroll = 0;
|
|||
int breaks = 0;
|
||||
int font_height = 0;
|
||||
|
||||
static u32 selectedPartitionIndex;
|
||||
static u32 selectedFileIndex;
|
||||
|
||||
static bool highlight = false;
|
||||
|
||||
static bool isFat32 = false, dumpCert = false, trimDump = false, calcCrc = true;
|
||||
|
||||
static u32 selectedOption;
|
||||
|
||||
static FsFileSystem fs;
|
||||
|
||||
static char statusMessage[2048] = {'\0'};
|
||||
static int statusMessageFadeout = 0;
|
||||
|
||||
static char fileCopyPath[NAME_BUF_LEN * 2] = {'\0'};
|
||||
|
||||
static int headlineCnt = 0;
|
||||
|
||||
u64 freeSpace = 0;
|
||||
|
@ -272,19 +273,18 @@ void uiUpdateStatusMsg()
|
|||
{
|
||||
if (!strlen(statusMessage) || !statusMessageFadeout) return;
|
||||
|
||||
uiFill(0, FB_HEIGHT - (font_height * 2), FB_WIDTH, font_height * 2, BG_COLOR_RGB, BG_COLOR_RGB, BG_COLOR_RGB);
|
||||
|
||||
if ((statusMessageFadeout - 4) > BG_COLOR_RGB)
|
||||
{
|
||||
uiFill(0, FB_HEIGHT - (font_height * 2), FB_WIDTH, font_height * 2, BG_COLOR_RGB, BG_COLOR_RGB, BG_COLOR_RGB);
|
||||
|
||||
int fadeout = (statusMessageFadeout > 255 ? 255 : statusMessageFadeout);
|
||||
uiDrawString(statusMessage, 0, FB_HEIGHT - (font_height * 2), fadeout, fadeout, fadeout);
|
||||
uiRefreshDisplay();
|
||||
|
||||
statusMessageFadeout -= 4;
|
||||
} else {
|
||||
uiFill(0, FB_HEIGHT - (font_height * 2), FB_WIDTH, font_height * 2, BG_COLOR_RGB, BG_COLOR_RGB, BG_COLOR_RGB);
|
||||
statusMessageFadeout = 0;
|
||||
}
|
||||
|
||||
uiRefreshDisplay();
|
||||
}
|
||||
|
||||
void uiPleaseWait()
|
||||
|
@ -411,6 +411,12 @@ int uiInit()
|
|||
/* Disable screen dimming and auto sleep */
|
||||
appletSetMediaPlaybackState(true);
|
||||
|
||||
/* Get applet type */
|
||||
programAppletType = appletGetAppletType();
|
||||
|
||||
/* Block HOME menu button presses if we're running as a regular application or a system application */
|
||||
if (programAppletType == AppletType_Application || programAppletType == AppletType_SystemApplication) appletBeginBlockingHomeButton(0);
|
||||
|
||||
/* Clear screen */
|
||||
uiClearScreen();
|
||||
|
||||
|
@ -419,6 +425,9 @@ int uiInit()
|
|||
|
||||
void uiDeinit()
|
||||
{
|
||||
/* Unblock HOME menu button presses if we're running as a regular application or a system application */
|
||||
if (programAppletType == AppletType_Application || programAppletType == AppletType_SystemApplication) appletEndBlockingHomeButton();
|
||||
|
||||
/* Enable screen dimming and auto sleep */
|
||||
appletSetMediaPlaybackState(false);
|
||||
|
||||
|
@ -459,6 +468,7 @@ UIResult uiProcess()
|
|||
int menuItemsCount = 0;
|
||||
|
||||
u32 keysDown;
|
||||
u32 keysHeld;
|
||||
|
||||
uiPrintHeadline();
|
||||
loadGameCardInfo();
|
||||
|
@ -588,11 +598,7 @@ UIResult uiProcess()
|
|||
menu = (const char**)filenames;
|
||||
menuItemsCount = filenamesCount;
|
||||
|
||||
uiDrawString((hfs0_partition_cnt == GAMECARD_TYPE1_PARTITION_CNT ? viewGameCardFsType1MenuItems[selectedOption] : viewGameCardFsType2MenuItems[selectedOption]), 0, breaks * font_height, 115, 115, 255);
|
||||
breaks += 2;
|
||||
|
||||
snprintf(titlebuf, sizeof(titlebuf) / sizeof(titlebuf[0]), "Current directory: %s", currentDirectory);
|
||||
uiDrawString(titlebuf, 0, breaks * font_height, 255, 255, 255);
|
||||
uiDrawString((hfs0_partition_cnt == GAMECARD_TYPE1_PARTITION_CNT ? viewGameCardFsType1MenuItems[selectedPartitionIndex] : viewGameCardFsType2MenuItems[selectedPartitionIndex]), 0, breaks * font_height, 115, 115, 255);
|
||||
breaks += 2;
|
||||
|
||||
snprintf(titlebuf, sizeof(titlebuf) / sizeof(titlebuf[0]), "File count: %d | Current file: %d", menuItemsCount, cursor + 1);
|
||||
|
@ -677,18 +683,10 @@ UIResult uiProcess()
|
|||
|
||||
hidScanInput();
|
||||
keysDown = hidKeysDown(CONTROLLER_P1_AUTO);
|
||||
keysHeld = hidKeysHeld(CONTROLLER_P1_AUTO);
|
||||
|
||||
// Exit
|
||||
if (keysDown & KEY_PLUS)
|
||||
{
|
||||
if (uiState == stateViewGameCardFsBrowser)
|
||||
{
|
||||
fsdevUnmountDevice("view");
|
||||
fsFsClose(&fs);
|
||||
}
|
||||
|
||||
res = resultExit;
|
||||
}
|
||||
if (keysDown & KEY_PLUS) res = resultExit;
|
||||
|
||||
// Process key inputs only if the UI state hasn't been changed
|
||||
if (res == resultNone)
|
||||
|
@ -698,11 +696,7 @@ UIResult uiProcess()
|
|||
if (uiState == stateXciDumpMenu)
|
||||
{
|
||||
// Select
|
||||
if ((keysDown & KEY_A) && cursor == 0)
|
||||
{
|
||||
selectedOption = (u32)cursor;
|
||||
res = resultDumpXci;
|
||||
}
|
||||
if ((keysDown & KEY_A) && cursor == 0) res = resultDumpXci;
|
||||
|
||||
// Back
|
||||
if (keysDown & KEY_B) res = resultShowMainMenu;
|
||||
|
@ -752,10 +746,10 @@ UIResult uiProcess()
|
|||
}
|
||||
|
||||
// Go up
|
||||
if (keysDown & KEY_UP) scrollAmount = -1;
|
||||
if ((keysDown & KEY_DUP) || (keysHeld & KEY_LSTICK_UP) || (keysHeld & KEY_RSTICK_UP)) scrollAmount = -1;
|
||||
|
||||
// Go down
|
||||
if (keysDown & KEY_DOWN) scrollAmount = 1;
|
||||
if ((keysDown & KEY_DDOWN) || (keysHeld & KEY_LSTICK_DOWN) || (keysHeld & KEY_RSTICK_DOWN)) scrollAmount = 1;
|
||||
} else {
|
||||
// Select
|
||||
if (keysDown & KEY_A)
|
||||
|
@ -791,48 +785,27 @@ UIResult uiProcess()
|
|||
} else
|
||||
if (uiState == stateRawPartitionDumpMenu)
|
||||
{
|
||||
selectedOption = (u32)cursor;
|
||||
// Save selected partition index
|
||||
selectedPartitionIndex = (u32)cursor;
|
||||
res = resultDumpRawPartition;
|
||||
} else
|
||||
if (uiState == statePartitionDataDumpMenu)
|
||||
{
|
||||
selectedOption = (u32)cursor;
|
||||
// Save selected partition index
|
||||
selectedPartitionIndex = (u32)cursor;
|
||||
res = resultDumpPartitionData;
|
||||
} else
|
||||
if (uiState == stateViewGameCardFsMenu)
|
||||
{
|
||||
selectedOption = (u32)cursor;
|
||||
// Save selected partition index
|
||||
selectedPartitionIndex = (u32)cursor;
|
||||
res = resultShowViewGameCardFsGetList;
|
||||
} else
|
||||
if (uiState == stateViewGameCardFsBrowser)
|
||||
{
|
||||
char *selectedPath = (char*)malloc(strlen(currentDirectory) + 1 + strlen(filenames[cursor]) + 2);
|
||||
memset(selectedPath, 0, strlen(currentDirectory) + 1 + strlen(filenames[cursor]) + 2);
|
||||
|
||||
if (strlen(filenames[cursor]) == 2 && !strcmp(filenames[cursor], ".."))
|
||||
{
|
||||
for(i = (strlen(currentDirectory) - 1); i >= 0; i--)
|
||||
{
|
||||
if (currentDirectory[i] == '/')
|
||||
{
|
||||
strncpy(selectedPath, currentDirectory, i);
|
||||
selectedPath[i] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
snprintf(selectedPath, strlen(currentDirectory) + 1 + strlen(filenames[cursor]) + 2, "%s/%s", currentDirectory, filenames[cursor]);
|
||||
}
|
||||
|
||||
if (isDirectory(selectedPath))
|
||||
{
|
||||
enterDirectory(selectedPath);
|
||||
} else {
|
||||
snprintf(fileCopyPath, sizeof(fileCopyPath) / sizeof(fileCopyPath[0]), "%s", selectedPath);
|
||||
res = resultViewGameCardFsBrowserCopyFile;
|
||||
}
|
||||
|
||||
free(selectedPath);
|
||||
// Save selected file index
|
||||
selectedFileIndex = (u32)cursor;
|
||||
res = resultViewGameCardFsBrowserCopyFile;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -845,40 +818,24 @@ UIResult uiProcess()
|
|||
} else
|
||||
if (uiState == stateViewGameCardFsBrowser)
|
||||
{
|
||||
if (!strcmp(currentDirectory, "view:/") && strlen(currentDirectory) == 6)
|
||||
{
|
||||
fsdevUnmountDevice("view");
|
||||
fsFsClose(&fs);
|
||||
|
||||
res = resultShowViewGameCardFsMenu;
|
||||
} else {
|
||||
char *selectedPath = (char*)malloc(strlen(currentDirectory) + 1);
|
||||
memset(selectedPath, 0, strlen(currentDirectory) + 1);
|
||||
|
||||
for(i = (strlen(currentDirectory) - 1); i >= 0; i--)
|
||||
{
|
||||
if (currentDirectory[i] == '/')
|
||||
{
|
||||
strncpy(selectedPath, currentDirectory, i);
|
||||
selectedPath[i] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isDirectory(selectedPath)) enterDirectory(selectedPath);
|
||||
|
||||
free(selectedPath);
|
||||
}
|
||||
free(partitionHfs0Header);
|
||||
partitionHfs0Header = NULL;
|
||||
partitionHfs0HeaderOffset = 0;
|
||||
partitionHfs0HeaderSize = 0;
|
||||
partitionHfs0FileCount = 0;
|
||||
partitionHfs0StrTableSize = 0;
|
||||
|
||||
res = resultShowViewGameCardFsMenu;
|
||||
}
|
||||
}
|
||||
|
||||
// Go up
|
||||
if (keysDown & KEY_UP) scrollAmount = -1;
|
||||
if (keysDown & KEY_LEFT) scrollAmount = -5;
|
||||
if ((keysDown & KEY_DUP) || (keysHeld & KEY_LSTICK_UP) || (keysHeld & KEY_RSTICK_UP)) scrollAmount = -1;
|
||||
if ((keysDown & KEY_DLEFT) || (keysHeld & KEY_LSTICK_LEFT) || (keysHeld & KEY_RSTICK_LEFT)) scrollAmount = -5;
|
||||
|
||||
// Go down
|
||||
if (keysDown & KEY_DOWN) scrollAmount = 1;
|
||||
if (keysDown & KEY_RIGHT) scrollAmount = 5;
|
||||
if ((keysDown & KEY_DDOWN) || (keysHeld & KEY_LSTICK_DOWN) || (keysHeld & KEY_RSTICK_DOWN)) scrollAmount = 1;
|
||||
if ((keysDown & KEY_DRIGHT) || (keysHeld & KEY_LSTICK_RIGHT) || (keysHeld & KEY_RSTICK_RIGHT)) scrollAmount = 5;
|
||||
}
|
||||
|
||||
// Calculate scroll only if the UI state hasn't been changed
|
||||
|
@ -930,6 +887,8 @@ UIResult uiProcess()
|
|||
uiDrawString(titlebuf, 0, breaks * font_height, 115, 115, 255);
|
||||
breaks += 2;
|
||||
|
||||
uiRefreshDisplay();
|
||||
|
||||
dumpGameCartridge(&fsOperatorInstance, isFat32, dumpCert, trimDump, calcCrc);
|
||||
|
||||
waitForButtonPress();
|
||||
|
@ -939,11 +898,13 @@ UIResult uiProcess()
|
|||
} else
|
||||
if (uiState == stateDumpRawPartition)
|
||||
{
|
||||
snprintf(titlebuf, sizeof(titlebuf) / sizeof(titlebuf[0]), "Raw %s", (hfs0_partition_cnt == GAMECARD_TYPE1_PARTITION_CNT ? partitionDumpType1MenuItems[selectedOption] : partitionDumpType2MenuItems[selectedOption]));
|
||||
snprintf(titlebuf, sizeof(titlebuf) / sizeof(titlebuf[0]), "Raw %s", (hfs0_partition_cnt == GAMECARD_TYPE1_PARTITION_CNT ? partitionDumpType1MenuItems[selectedPartitionIndex] : partitionDumpType2MenuItems[selectedPartitionIndex]));
|
||||
uiDrawString(titlebuf, 0, breaks * font_height, 115, 115, 255);
|
||||
breaks += 2;
|
||||
|
||||
dumpRawPartition(&fsOperatorInstance, selectedOption, true);
|
||||
uiRefreshDisplay();
|
||||
|
||||
dumpRawPartition(&fsOperatorInstance, selectedPartitionIndex, true);
|
||||
|
||||
waitForButtonPress();
|
||||
|
||||
|
@ -952,11 +913,13 @@ UIResult uiProcess()
|
|||
} else
|
||||
if (uiState == stateDumpPartitionData)
|
||||
{
|
||||
snprintf(titlebuf, sizeof(titlebuf) / sizeof(titlebuf[0]), "Data %s", (hfs0_partition_cnt == GAMECARD_TYPE1_PARTITION_CNT ? partitionDumpType1MenuItems[selectedOption] : partitionDumpType2MenuItems[selectedOption]));
|
||||
snprintf(titlebuf, sizeof(titlebuf) / sizeof(titlebuf[0]), "Data %s", (hfs0_partition_cnt == GAMECARD_TYPE1_PARTITION_CNT ? partitionDumpType1MenuItems[selectedPartitionIndex] : partitionDumpType2MenuItems[selectedPartitionIndex]));
|
||||
uiDrawString(titlebuf, 0, breaks * font_height, 115, 115, 255);
|
||||
breaks += 2;
|
||||
|
||||
dumpPartitionData(&fsOperatorInstance, selectedOption);
|
||||
uiRefreshDisplay();
|
||||
|
||||
dumpPartitionData(&fsOperatorInstance, selectedPartitionIndex);
|
||||
|
||||
waitForButtonPress();
|
||||
|
||||
|
@ -965,13 +928,15 @@ UIResult uiProcess()
|
|||
} else
|
||||
if (uiState == stateViewGameCardFsGetList)
|
||||
{
|
||||
uiDrawString((hfs0_partition_cnt == GAMECARD_TYPE1_PARTITION_CNT ? viewGameCardFsType1MenuItems[selectedOption] : viewGameCardFsType1MenuItems[selectedOption]), 0, breaks * font_height, 115, 115, 255);
|
||||
uiDrawString((hfs0_partition_cnt == GAMECARD_TYPE1_PARTITION_CNT ? viewGameCardFsType1MenuItems[selectedPartitionIndex] : viewGameCardFsType2MenuItems[selectedPartitionIndex]), 0, breaks * font_height, 115, 115, 255);
|
||||
breaks += 2;
|
||||
|
||||
if (mountViewPartition(&fsOperatorInstance, &fs, selectedOption))
|
||||
uiRefreshDisplay();
|
||||
|
||||
if (getHfs0FileList(&fsOperatorInstance, selectedPartitionIndex))
|
||||
{
|
||||
enterDirectory("view:/");
|
||||
|
||||
cursor = 0;
|
||||
scroll = 0;
|
||||
res = resultShowViewGameCardFsBrowser;
|
||||
} else {
|
||||
breaks += 2;
|
||||
|
@ -981,45 +946,13 @@ UIResult uiProcess()
|
|||
} else
|
||||
if (uiState == stateViewGameCardFsBrowserCopyFile)
|
||||
{
|
||||
uiDrawString("Manual File Dump", 0, breaks * font_height, 115, 115, 255);
|
||||
snprintf(titlebuf, sizeof(titlebuf) / sizeof(titlebuf[0]), "Manual File Dump: %s (Partition %u [%s])", filenames[selectedFileIndex], selectedPartitionIndex, GAMECARD_PARTITION_NAME(hfs0_partition_cnt, selectedPartitionIndex));
|
||||
uiDrawString(titlebuf, 0, breaks * font_height, 115, 115, 255);
|
||||
breaks += 2;
|
||||
|
||||
FILE *inFile = fopen(fileCopyPath, "rb");
|
||||
if (inFile)
|
||||
{
|
||||
fseek(inFile, 0L, SEEK_END);
|
||||
u64 input_filesize = ftell(inFile);
|
||||
fclose(inFile);
|
||||
|
||||
if (input_filesize <= freeSpace)
|
||||
{
|
||||
char destCopyPath[NAME_BUF_LEN] = {'\0'};
|
||||
|
||||
for(i = (strlen(fileCopyPath) - 1); i >= 0; i--)
|
||||
{
|
||||
if (fileCopyPath[i] == '/')
|
||||
{
|
||||
snprintf(destCopyPath, sizeof(destCopyPath) / sizeof(destCopyPath[0]), "sdmc:/%s v%u (%016lX) - Partition %u (%s)", fixedGameCardName, gameCardVersion, gameCardTitleID, selectedOption, GAMECARD_PARTITION_NAME(hfs0_partition_cnt, selectedOption));
|
||||
mkdir(destCopyPath, 0744);
|
||||
|
||||
snprintf(destCopyPath, sizeof(destCopyPath) / sizeof(destCopyPath[0]), "sdmc:/%s v%u (%016lX) - Partition %u (%s)/%.*s", fixedGameCardName, gameCardVersion, gameCardTitleID, selectedOption, GAMECARD_PARTITION_NAME(hfs0_partition_cnt, selectedOption), (int)(strlen(fileCopyPath) - i), fileCopyPath + i + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uiDrawString("Hold B to cancel.", 0, breaks * font_height, 255, 255, 255);
|
||||
breaks += 2;
|
||||
|
||||
uiDrawString("Do not press the HOME button. Doing so could corrupt the SD card filesystem.", 0, breaks * font_height, 255, 0, 0);
|
||||
breaks += 2;
|
||||
|
||||
copyFile(fileCopyPath, destCopyPath, true, true);
|
||||
} else {
|
||||
uiDrawString("Error: not enough free space available in the SD card.", 0, breaks * font_height, 255, 0, 0);
|
||||
}
|
||||
} else {
|
||||
uiDrawString("Error: unable to get input file size.", 0, breaks * font_height, 255, 0, 0);
|
||||
}
|
||||
uiRefreshDisplay();
|
||||
|
||||
dumpFileFromPartition(&fsOperatorInstance, selectedPartitionIndex, selectedFileIndex, filenames[selectedFileIndex]);
|
||||
|
||||
breaks += 2;
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <errno.h>
|
||||
#include <math.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statvfs.h>
|
||||
|
@ -53,8 +54,6 @@ static char *result_buf = NULL;
|
|||
static size_t result_sz = 0;
|
||||
static size_t result_written = 0;
|
||||
|
||||
char currentDirectory[NAME_BUF_LEN] = {'\0'};
|
||||
|
||||
char *filenameBuffer = NULL;
|
||||
char *filenames[FILENAME_MAX_CNT];
|
||||
int filenamesCount = 0;
|
||||
|
@ -65,6 +64,8 @@ Handle fsGameCardEventHandle;
|
|||
Event fsGameCardKernelEvent;
|
||||
UEvent exitEvent;
|
||||
|
||||
AppletType programAppletType;
|
||||
|
||||
bool gameCardInserted;
|
||||
|
||||
u64 gameCardSize = 0, trimmedCardSize = 0;
|
||||
|
@ -75,7 +76,8 @@ u64 hfs0_offset = 0, hfs0_size = 0;
|
|||
u32 hfs0_partition_cnt = 0;
|
||||
|
||||
char *partitionHfs0Header = NULL;
|
||||
u64 partitionHfs0HeaderSize = 0;
|
||||
u64 partitionHfs0HeaderOffset = 0, partitionHfs0HeaderSize = 0;
|
||||
u32 partitionHfs0FileCount = 0, partitionHfs0StrTableSize = 0;
|
||||
|
||||
u64 gameCardTitleID = 0;
|
||||
u32 gameCardVersion = 0;
|
||||
|
@ -287,7 +289,10 @@ void loadGameCardInfo()
|
|||
{
|
||||
free(partitionHfs0Header);
|
||||
partitionHfs0Header = NULL;
|
||||
partitionHfs0HeaderOffset = 0;
|
||||
partitionHfs0HeaderSize = 0;
|
||||
partitionHfs0FileCount = 0;
|
||||
partitionHfs0StrTableSize = 0;
|
||||
}
|
||||
|
||||
gameCardTitleID = 0;
|
||||
|
@ -379,76 +384,44 @@ void waitForButtonPress()
|
|||
{
|
||||
hidScanInput();
|
||||
u32 keysDown = hidKeysDown(CONTROLLER_P1_AUTO);
|
||||
if (keysDown && !(keysDown & KEY_TOUCH)) break;
|
||||
if (keysDown && !((keysDown & KEY_TOUCH) || (keysDown & KEY_LSTICK_LEFT) || (keysDown & KEY_LSTICK_RIGHT) || (keysDown & KEY_LSTICK_UP) || (keysDown & KEY_LSTICK_DOWN) || \
|
||||
(keysDown & KEY_RSTICK_LEFT) || (keysDown & KEY_RSTICK_RIGHT) || (keysDown & KEY_RSTICK_UP) || (keysDown & KEY_RSTICK_DOWN))) break;
|
||||
}
|
||||
}
|
||||
|
||||
bool isDirectory(char *path)
|
||||
void addStringToFilenameBuffer(const char *string, char **nextFilename)
|
||||
{
|
||||
DIR* dir = opendir(path);
|
||||
if (!dir) return false;
|
||||
|
||||
closedir(dir);
|
||||
return true;
|
||||
}
|
||||
|
||||
void addString(char **filenames, int *filenamesCount, char **nextFilename, const char *string)
|
||||
{
|
||||
filenames[(*filenamesCount)++] = *nextFilename;
|
||||
filenames[filenamesCount++] = *nextFilename;
|
||||
strcpy(*nextFilename, string);
|
||||
*nextFilename += strlen(string) + 1;
|
||||
*nextFilename += (strlen(string) + 1);
|
||||
}
|
||||
|
||||
static int sortAlpha(const void* a, const void* b)
|
||||
void removeDirectory(const char *path)
|
||||
{
|
||||
return strcasecmp(*((const char**)a), *((const char**)b));
|
||||
}
|
||||
|
||||
void getDirectoryContents(char *filenameBuffer, char **filenames, int *filenamesCount, const char *directory, bool skipParent)
|
||||
{
|
||||
struct dirent *ent;
|
||||
int i, maxFilenamesCount = *filenamesCount;
|
||||
char *nextFilename = filenameBuffer;
|
||||
struct dirent* ent;
|
||||
char cur_path[NAME_BUF_LEN] = {'\0'};
|
||||
|
||||
char *slash = (char*)malloc(strlen(directory) + 2);
|
||||
memset(slash, 0, strlen(directory) + 2);
|
||||
snprintf(slash, strlen(directory) + 2, "%s/", directory);
|
||||
|
||||
*filenamesCount = 0;
|
||||
|
||||
if (!skipParent) addString(filenames, filenamesCount, &nextFilename, "..");
|
||||
|
||||
DIR* dir = opendir(slash);
|
||||
DIR *dir = opendir(path);
|
||||
if (dir)
|
||||
{
|
||||
for(i = 0; i < maxFilenamesCount; i++)
|
||||
while ((ent = readdir(dir)) != NULL)
|
||||
{
|
||||
ent = readdir(dir);
|
||||
if (!ent) break;
|
||||
|
||||
if ((strlen(ent->d_name) == 1 && !strcmp(ent->d_name, ".")) || (strlen(ent->d_name) == 2 && !strcmp(ent->d_name, ".."))) continue;
|
||||
|
||||
addString(filenames, filenamesCount, &nextFilename, ent->d_name);
|
||||
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 {
|
||||
remove(cur_path);
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
rmdir(path);
|
||||
}
|
||||
|
||||
free(slash);
|
||||
|
||||
// ".." should stay at the top
|
||||
qsort(filenames + 1, (*filenamesCount) - 1, sizeof(char*), &sortAlpha);
|
||||
}
|
||||
|
||||
void enterDirectory(const char *path)
|
||||
{
|
||||
snprintf(currentDirectory, sizeof(currentDirectory) / sizeof(currentDirectory[0]), "%s", path);
|
||||
|
||||
filenamesCount = FILENAME_MAX_CNT;
|
||||
getDirectoryContents(filenameBuffer, &filenames[0], &filenamesCount, currentDirectory, (!strcmp(currentDirectory, "view:/") && strlen(currentDirectory) == 6));
|
||||
|
||||
cursor = 0;
|
||||
scroll = 0;
|
||||
}
|
||||
|
||||
bool parseNSWDBRelease(xmlDocPtr doc, xmlNodePtr cur, u32 crc)
|
||||
|
@ -672,7 +645,13 @@ void updateNSWDBXml()
|
|||
{
|
||||
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Downloading XML database from \"%s\", please wait...", nswReleasesXmlUrl);
|
||||
uiDrawString(strbuf, 0, breaks * font_height, 255, 255, 255);
|
||||
breaks++;
|
||||
breaks += 2;
|
||||
|
||||
if (programAppletType != AppletType_Application && programAppletType != AppletType_SystemApplication)
|
||||
{
|
||||
uiDrawString("Do not press the HOME button. Doing so could corrupt the SD card filesystem.", 0, breaks * font_height, 255, 0, 0);
|
||||
breaks += 2;
|
||||
}
|
||||
|
||||
uiRefreshDisplay();
|
||||
|
||||
|
@ -930,6 +909,12 @@ void updateApplication()
|
|||
uiDrawString("Please wait...", 0, breaks * font_height, 255, 255, 255);
|
||||
breaks += 2;
|
||||
|
||||
if (programAppletType != AppletType_Application && programAppletType != AppletType_SystemApplication)
|
||||
{
|
||||
uiDrawString("Do not press the HOME button. Doing so could corrupt the SD card filesystem.", 0, breaks * font_height, 255, 0, 0);
|
||||
breaks += 2;
|
||||
}
|
||||
|
||||
uiRefreshDisplay();
|
||||
|
||||
gcDumpToolNro = fopen(gcDumpToolTmpPath, "wb");
|
||||
|
|
|
@ -26,12 +26,8 @@ void fsGameCardDetectionThreadFunc(void *arg);
|
|||
|
||||
void delay(u8 seconds);
|
||||
|
||||
bool getGameCardTitleIDAndVersion(u64 *titleID, u32 *version);
|
||||
|
||||
void convertTitleVersionToDecimal(u32 version, char *versionBuf, int versionBufSize);
|
||||
|
||||
bool getGameCardControlNacp(u64 titleID, char *nameBuf, int nameBufSize, char *authorBuf, int authorBufSize);
|
||||
|
||||
void removeIllegalCharacters(char *name);
|
||||
|
||||
void strtrim(char *str);
|
||||
|
@ -44,13 +40,9 @@ void convertSize(u64 size, char *out, int bufsize);
|
|||
|
||||
void waitForButtonPress();
|
||||
|
||||
bool isDirectory(char *path);
|
||||
void addStringToFilenameBuffer(const char *string, char **nextFilename);
|
||||
|
||||
void addString(char **filenames, int *filenamesCount, char **nextFilename, const char *string);
|
||||
|
||||
void getDirectoryContents(char *filenameBuffer, char **filenames, int *filenamesCount, const char *directory, bool skipParent);
|
||||
|
||||
void enterDirectory(const char *path);
|
||||
void removeDirectory(const char *path);
|
||||
|
||||
void gameCardDumpNSWDBCheck(u32 crc);
|
||||
|
||||
|
|
Loading…
Reference in a new issue