mirror of
https://github.com/Ryuzaki-MrL/savemii.git
synced 2026-04-25 07:22:28 -05:00
Add vWii savefile backup/restore
This commit is contained in:
parent
c1fcc54831
commit
ba51de6c57
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -4,10 +4,10 @@
|
|||
<coder>Ryuzaki_MrL</coder>
|
||||
<version>1.0.0</version>
|
||||
<release_date>20170404000000</release_date>
|
||||
<short_description>Wii U Save Manager</short_description>
|
||||
<long_description>Wii U Save Manager
|
||||
<short_description>WiiU/vWii Save Manager</short_description>
|
||||
<long_description>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.</long_description>
|
||||
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.</long_description>
|
||||
</app>
|
||||
138
src/main.c
138
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);
|
||||
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[titlecount].shortname, (char*)xmlNodeGetContent(cur_node));
|
||||
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");
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
#include <sys/dirent.h>
|
||||
|
||||
#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);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef _SAVEMNG_H_
|
||||
#define _SAVEMNG_H_
|
||||
|
||||
#include <sys/dirent.h>
|
||||
#include <gctypes.h>
|
||||
#include <fat.h>
|
||||
#include <iosuhax.h>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user