diff --git a/README.md b/README.md
index e33c896..775ac56 100644
--- a/README.md
+++ b/README.md
@@ -1,16 +1,15 @@
# savemii
-Wii U Save Manager
+WiiU/vWii Save Manager
**You need to run iosuhax/mocha cfw first in order for this homebrew to work.**
-This homebrew allows you to backup your Wii U savegames to the SD card and also restore them.
+This homebrew allows you to backup your Wii U and vWii savegames to the SD card and also restore them.
Up to 256 backups can be made per title.
Backups are stored in sd:/wiiu/apps/savemii/backups.
Please report any issues that may occur.
TODO:
-- add vWii support
- installable package
Credits:
diff --git a/meta/meta.xml b/meta/meta.xml
index 7b1c63f..2943ec7 100644
--- a/meta/meta.xml
+++ b/meta/meta.xml
@@ -4,10 +4,10 @@
Ryuzaki_MrL
1.0.0
20170404000000
- Wii U Save Manager
- Wii U Save Manager
+ WiiU/vWii Save Manager
+ WiiU/vWii Save Manager
You need to run iosuhax/mocha cfw first in order for this homebrew to work.
-This homebrew allows you to backup your Wii U savegames to the SD card and also restore them. Up to 256 backups can be made per title. Backups are stored in sd:/wiiu/apps/savemii/backups.
+This homebrew allows you to backup your Wii U and vWii savegames to the SD card and also restore them. Up to 256 backups can be made per title. Backups are stored in sd:/wiiu/apps/savemii/backups.
\ No newline at end of file
diff --git a/src/main.c b/src/main.c
index 08eff4b..d5d3c8e 100644
--- a/src/main.c
+++ b/src/main.c
@@ -16,7 +16,7 @@
u8 slot = 0;
int menu = 0, mode = 0, task = 0, targ = 0;
int cursor = 0, scroll = 0;
-int titlecount = 0;
+int titleswiiu = 0, titlesvwii = 0;
typedef struct {
u32 highID;
@@ -57,7 +57,7 @@ void MCPHookClose() {
mcp_hook_fd = -1;
}
-Title* loadTitles() {
+Title* loadWiiUTitles() {
int mcp_handle = MCP_Open();
int count = MCP_TitleCount(mcp_handle);
@@ -69,6 +69,10 @@ Title* loadTitles() {
MCP_Close(mcp_handle);
Title* titles = malloc(receivedCount*sizeof(Title));
+ if (!titles) {
+ promptError("Out of memory.");
+ return NULL;
+ }
for (int i = 0; i < receivedCount; i++) {
@@ -86,31 +90,39 @@ Title* loadTitles() {
size_t xmlSize = ftell(xmlFile);
fseek(xmlFile, 0, SEEK_SET);
char* xmlBuf = malloc(xmlSize+1);
- memset(xmlBuf, 0, xmlSize+1);
- fread(xmlBuf, 1, xmlSize, xmlFile);
- fclose(xmlFile);
-
- xmlDocPtr tmp = xmlReadMemory(xmlBuf, xmlSize, "meta.xml", "utf-8", 0);
- xmlNode* root_element = xmlDocGetRootElement(tmp);
- xmlNode* cur_node = NULL;
- for (cur_node = root_element->children; cur_node; cur_node = cur_node->next) {
- if (
- (cur_node->type != XML_ELEMENT_NODE) ||
- (memcmp(cur_node->name, "shortname_en", 13) != 0) ||
- (xmlNodeGetContent(cur_node) == NULL) ||
- (!strlen((char*)xmlNodeGetContent(cur_node)))
- ) continue;
- strcpy(titles[titlecount].shortname, (char*)xmlNodeGetContent(cur_node));
- }
+ if (xmlBuf) {
+ memset(xmlBuf, 0, xmlSize+1);
+ fread(xmlBuf, 1, xmlSize, xmlFile);
+ fclose(xmlFile);
+
+ xmlDocPtr tmp = xmlReadMemory(xmlBuf, xmlSize, "meta.xml", "utf-8", 0);
+ xmlNode* root_element = xmlDocGetRootElement(tmp);
+ xmlNode* cur_node = NULL;
+ for (cur_node = root_element->children; cur_node; cur_node = cur_node->next) {
+ if (
+ (cur_node->type != XML_ELEMENT_NODE) ||
+ (memcmp(cur_node->name, "shortname_en", 13) != 0) ||
+ (xmlNodeGetContent(cur_node) == NULL) ||
+ (!strlen((char*)xmlNodeGetContent(cur_node)))
+ ) continue;
+ strcpy(titles[titleswiiu].shortname, (char*)xmlNodeGetContent(cur_node));
+ }
- xmlFreeDoc(tmp);
- free(xmlBuf);
+ xmlFreeDoc(tmp);
+ free(xmlBuf);
+ }
}
- titles[titlecount].highID = highID;
- titles[titlecount].lowID = lowID;
- titles[titlecount].isTitleOnUSB = isTitleOnUSB;
- titlecount++;
+ titles[titleswiiu].highID = highID;
+ titles[titleswiiu].lowID = lowID;
+ titles[titleswiiu].isTitleOnUSB = isTitleOnUSB;
+ titleswiiu++;
+
+ OSScreenClearBufferEx(0, 0);
+ OSScreenClearBufferEx(1, 0);
+ console_print_pos(0, 0, "Loaded %i Wii U titles.", titleswiiu);
+ OSScreenFlipBuffersEx(0);
+ OSScreenFlipBuffersEx(1);
}
@@ -119,6 +131,66 @@ Title* loadTitles() {
}
+Title* loadWiiTitles() {
+
+ struct dirent *dirent = NULL;
+ DIR *dir = NULL;
+
+ dir = opendir("slccmpt01:/title/00010000");
+ if (dir == NULL) {
+ promptError("Failed to open directory.");
+ return NULL;
+ }
+
+ while ((dirent = readdir(dir)) != 0) {
+ if(strcmp(dirent->d_name, "..")==0 || strcmp(dirent->d_name, ".")==0) continue;
+ titlesvwii++;
+ } rewinddir(dir);
+
+ Title* titles = malloc(titlesvwii*sizeof(Title));
+ if (!titles) {
+ promptError("Out of memory.");
+ return NULL;
+ }
+
+ int i = 0;
+ while ((dirent = readdir(dir)) != 0) {
+
+ if(strcmp(dirent->d_name, "..")==0 || strcmp(dirent->d_name, ".")==0) continue;
+
+ char path[256];
+ sprintf(path, "slccmpt01:/title/00010000/%s/data/banner.bin", dirent->d_name);
+ FILE* bnrFile = fopen(path, "rb");
+ if (bnrFile) {
+ fseek(bnrFile, 0x20, SEEK_SET);
+ u16* bnrBuf = (u16*)malloc(0x40);
+ if (bnrBuf) {
+ fread(bnrBuf, 0x02, 0x20, bnrFile);
+ fclose(bnrFile);
+ for (int j = 0, k = 0; j < 0x20; j++) {
+ titles[i].shortname[k++] = (char)bnrBuf[j];
+ }
+ free(bnrBuf);
+ }
+ }
+
+ titles[i].highID = 0x00010000;
+ titles[i].lowID = strtoul(dirent->d_name, NULL, 16);
+ i++;
+
+ OSScreenClearBufferEx(0, 0);
+ OSScreenClearBufferEx(1, 0);
+ console_print_pos(0, 1, "Loaded %i Wii titles.", i);
+ OSScreenFlipBuffersEx(0);
+ OSScreenFlipBuffersEx(1);
+
+ }
+
+ closedir(dir);
+ return titles;
+
+}
+
void unloadTitles(Title* titles) {
free(titles);
}
@@ -142,6 +214,9 @@ int Menu_Main(void) {
int fsaFd = IOSUHAX_FSA_Open();
if (fsaFd < 0) {
promptError("IOSUHAX_FSA_Open failed.");
+ if (mcp_hook_fd >= 0) MCPHookClose();
+ else IOSUHAX_Close();
+ return EXIT_SUCCESS;
}
mount_fs("slccmpt01", fsaFd, "/dev/slccmpt01", "/vol/storage_slccmpt01");
@@ -149,7 +224,8 @@ int Menu_Main(void) {
mount_fs("storage_usb", fsaFd, NULL, "/vol/storage_usb01");
ucls();
- Title* titles = loadTitles();
+ Title* wiiutitles = loadWiiUTitles();
+ Title* wiititles = loadWiiTitles();
while(1) {
@@ -159,10 +235,13 @@ int Menu_Main(void) {
console_print_pos(0, 0, "SaveMii v%u.%u.%u", VERSION_MAJOR, VERSION_MINOR, VERSION_MICRO);
console_print_pos(0, 1, "--------------------------------------------------");
+ Title* titles = mode ? wiititles : wiiutitles;
+ int count = mode ? titlesvwii : titleswiiu;
+
switch(menu) {
case 0: { // Main Menu
console_print_pos(0, 2, " Wii U Save Management");
- // console_print_pos(0, 3, " vWii Save Management");
+ console_print_pos(0, 3, " vWii Save Management");
console_print_pos(0, 2 + cursor, "->");
} break;
case 1: { // WiiU/vWii Save Management
@@ -171,9 +250,9 @@ int Menu_Main(void) {
// console_print_pos(0, 4, " Wipe savedata");
console_print_pos(0, 2 + cursor, "->");
} break;
- case 2: { // vWii/Wii U Title List
+ case 2: { // Wii/Wii U Title List
for (int i = 0; i < 14; i++) {
- if (i+scroll<0 || i+scroll>=titlecount) break;
+ if (i+scroll<0 || i+scroll>=count) break;
if (strlen(titles[i+scroll].shortname)) console_print_pos(0, i+2, " %s", titles[i+scroll].shortname);
else console_print_pos(0, i+2, " %08lx%08lx", titles[i+scroll].highID, titles[i+scroll].lowID);
} console_print_pos(0, 2 + cursor, "->");
@@ -193,7 +272,7 @@ int Menu_Main(void) {
updatePressedButtons();
updateHeldButtons();
- int entrycount = ((menu==0) ? 1 : ((menu==1) ? 2 : titlecount));
+ int entrycount = ((menu==0) ? 2 : ((menu==1) ? 2 : count));
if (isPressed(VPAD_BUTTON_DOWN) || isHeld(VPAD_BUTTON_DOWN)) {
if (entrycount<=14) cursor = (cursor + 1) % entrycount;
@@ -242,7 +321,8 @@ int Menu_Main(void) {
}
- unloadTitles(titles);
+ unloadTitles(wiiutitles);
+ unloadTitles(wiititles);
fatUnmount("sd");
fatUnmount("usb");
diff --git a/src/savemng.c b/src/savemng.c
index 64afdbe..2c5accf 100644
--- a/src/savemng.c
+++ b/src/savemng.c
@@ -1,5 +1,3 @@
-#include
-
#include "savemng.h"
#define BUFFER_SIZE 0x80000
@@ -129,7 +127,8 @@ void backupSavedata(u32 highID, u32 lowID, bool isUSB, int slot) {
char srcPath[256];
char dstPath[256];
- sprintf(srcPath, "storage_%s:/usr/save/%08x/%08x/user", isUSB ? "usb" : "mlc", highID, lowID);
+ const char* path = ((highID==0x00010000) ? "slccmpt01:/title" : (isUSB ? "storage_usb:/usr/save" : "storage_mlc:/usr/save"));
+ sprintf(srcPath, "%s/%08x/%08x/%s", path, highID, lowID, (highID==0x00010000) ? "data" : "user");
sprintf(dstPath, "sd:/wiiu/apps/savemii/backups/%08x%08x/%i", highID, lowID, slot);
DumpDir(srcPath, dstPath);
@@ -139,8 +138,9 @@ void restoreSavedata(u32 highID, u32 lowID, bool isUSB, int slot) {
char srcPath[256];
char dstPath[256];
+ const char* path = ((highID==0x00010000) ? "slccmpt01:/title" : (isUSB ? "storage_usb:/usr/save" : "storage_mlc:/usr/save"));
sprintf(srcPath, "sd:/wiiu/apps/savemii/backups/%08x%08x/%i", highID, lowID, slot);
- sprintf(dstPath, "storage_%s:/usr/save/%08x/%08x/user", isUSB ? "usb" : "mlc", highID, lowID);
+ sprintf(dstPath, "%s/%08x/%08x/%s", path, highID, lowID, (highID==0x00010000) ? "data" : "user");
DumpDir(srcPath, dstPath);
}
diff --git a/src/savemng.h b/src/savemng.h
index 69955ba..1e2be18 100644
--- a/src/savemng.h
+++ b/src/savemng.h
@@ -1,6 +1,7 @@
#ifndef _SAVEMNG_H_
#define _SAVEMNG_H_
+#include
#include
#include
#include