Skip to content

Commit 9dc7fb3

Browse files
committed
Update for v1.1.0
- Fix savedata backup/restore for disc titles - Separate backups by user - Add loadiine support - Move backups folder to sd:/wiiu (you need to move your backups to the new location) - Savedata wiping - Invert task and title selection - Code clean-up
1 parent ba51de6 commit 9dc7fb3

File tree

6 files changed

+407
-130
lines changed

6 files changed

+407
-130
lines changed

meta/meta.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<app version="1">
33
<name>SaveMii</name>
44
<coder>Ryuzaki_MrL</coder>
5-
<version>1.0.0</version>
5+
<version>1.1.0</version>
66
<release_date>20170404000000</release_date>
77
<short_description>WiiU/vWii Save Manager</short_description>
88
<long_description>WiiU/vWii Save Manager

src/lib_easy.c

Lines changed: 0 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -69,53 +69,6 @@ void uprintf(int x, int y, const char* format, ...) {
6969
curr_line=curr_line_tmp;
7070
}
7171

72-
void pause(int showmsg) {
73-
while(1) {
74-
if (showmsg) {
75-
OSScreenClearBufferEx(0, 0);
76-
OSScreenClearBufferEx(1, 0);
77-
console_print_pos(0, curr_line, "Press any key to continue...\n");
78-
OSScreenFlipBuffersEx(0);
79-
OSScreenFlipBuffersEx(1);
80-
}
81-
updatePressedButtons();
82-
if (isPressed(0xFFFF)) break;
83-
}
84-
}
85-
86-
int promptConfirm(const char* question) {
87-
ucls();
88-
const char* msg = "(A) Confirm - (B) Cancel";
89-
int ret = 0;
90-
while(1) {
91-
OSScreenClearBufferEx(0, 0);
92-
OSScreenClearBufferEx(1, 0);
93-
console_print_pos(25 - (strlen(question)>>1), 8, question);
94-
console_print_pos(25 - (strlen(msg)>>1), 10, msg);
95-
OSScreenFlipBuffersEx(0);
96-
OSScreenFlipBuffersEx(1);
97-
updatePressedButtons();
98-
if (isPressed(VPAD_BUTTON_A | VPAD_BUTTON_B | VPAD_BUTTON_HOME)) {
99-
ret = isPressed(VPAD_BUTTON_A);
100-
break;
101-
}
102-
}
103-
return ret;
104-
}
105-
106-
void promptError(const char* message) {
107-
ucls();
108-
while(1) {
109-
OSScreenClearBufferEx(0, 0);
110-
OSScreenClearBufferEx(1, 0);
111-
console_print_pos(25 - (strlen(message)>>1), 9, message);
112-
OSScreenFlipBuffersEx(0);
113-
OSScreenFlipBuffersEx(1);
114-
updatePressedButtons();
115-
if (isPressed(0xFFFF)) break;
116-
}
117-
}
118-
11972
int64_t uGetTime() {
12073
return OSGetTime()/SECS_TO_TICKS(1);
12174
}

src/lib_easy.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,6 @@ void ucls();
5050
void ScreenInit();
5151
void flipBuffers();
5252
void uprintf(int x, int y, const char* format, ...);
53-
void pause(int showmsg);
54-
int promptConfirm(const char* question);
55-
void promptError(const char* message);
5653
int64_t uGetTime();
5754
void updatePressedButtons();
5855
void updateHeldButtons();

src/main.c

Lines changed: 78 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,17 @@
1010
#include "savemng.h"
1111

1212
#define VERSION_MAJOR 1
13-
#define VERSION_MINOR 0
13+
#define VERSION_MINOR 1
1414
#define VERSION_MICRO 0
1515

1616
u8 slot = 0;
17+
bool allusers = 0, common = 1;
1718
int menu = 0, mode = 0, task = 0, targ = 0;
1819
int cursor = 0, scroll = 0;
1920
int titleswiiu = 0, titlesvwii = 0;
2021

21-
typedef struct {
22-
u32 highID;
23-
u32 lowID;
24-
char shortname[256];
25-
bool isTitleOnUSB;
26-
} Title;
27-
2822
//just to be able to call async
29-
void someFunc(void *arg)
30-
{
23+
void someFunc(void *arg) {
3124
(void)arg;
3225
}
3326

@@ -59,6 +52,7 @@ void MCPHookClose() {
5952

6053
Title* loadWiiUTitles() {
6154

55+
// Source: haxchi installer
6256
int mcp_handle = MCP_Open();
6357
int count = MCP_TitleCount(mcp_handle);
6458
int listSize = count*0x61;
@@ -79,7 +73,7 @@ Title* loadWiiUTitles() {
7973
char* element = tList+(i*0x61);
8074
u32 highID = *(u32*)(element), lowID = *(u32*)(element+4);
8175
if (highID!=0x00050000) continue;
82-
bool isTitleOnUSB = memcmp(element+0x56,"mlc",4)!=0;
76+
bool isTitleOnUSB = (memcmp(element+0x56,"usb",4)==0);
8377
char path[255];
8478
memset(path, 0, 255);
8579
sprintf(path, "storage_%s:/usr/title/%08x/%08x/meta/meta.xml", isTitleOnUSB ? "usb" : "mlc", highID, lowID);
@@ -101,11 +95,14 @@ Title* loadWiiUTitles() {
10195
for (cur_node = root_element->children; cur_node; cur_node = cur_node->next) {
10296
if (
10397
(cur_node->type != XML_ELEMENT_NODE) ||
104-
(memcmp(cur_node->name, "shortname_en", 13) != 0) ||
10598
(xmlNodeGetContent(cur_node) == NULL) ||
10699
(!strlen((char*)xmlNodeGetContent(cur_node)))
107100
) continue;
108-
strcpy(titles[titleswiiu].shortname, (char*)xmlNodeGetContent(cur_node));
101+
102+
if (!memcmp(cur_node->name, "shortname_en", 13))
103+
strcpy(titles[titleswiiu].shortName, (char*)xmlNodeGetContent(cur_node));
104+
if (!memcmp(cur_node->name, "product_code", 13))
105+
strcpy(titles[titleswiiu].productCode, (char*)(xmlNodeGetContent(cur_node)+6));
109106
}
110107

111108
xmlFreeDoc(tmp);
@@ -133,8 +130,8 @@ Title* loadWiiUTitles() {
133130

134131
Title* loadWiiTitles() {
135132

136-
struct dirent *dirent = NULL;
137-
DIR *dir = NULL;
133+
struct dirent* dirent = NULL;
134+
DIR* dir = NULL;
138135

139136
dir = opendir("slccmpt01:/title/00010000");
140137
if (dir == NULL) {
@@ -168,7 +165,7 @@ Title* loadWiiTitles() {
168165
fread(bnrBuf, 0x02, 0x20, bnrFile);
169166
fclose(bnrFile);
170167
for (int j = 0, k = 0; j < 0x20; j++) {
171-
titles[i].shortname[k++] = (char)bnrBuf[j];
168+
titles[i].shortName[k++] = (char)bnrBuf[j];
172169
}
173170
free(bnrBuf);
174171
}
@@ -192,7 +189,7 @@ Title* loadWiiTitles() {
192189
}
193190

194191
void unloadTitles(Title* titles) {
195-
free(titles);
192+
if (titles) free(titles);
196193
}
197194

198195
/* Entry point */
@@ -206,6 +203,7 @@ int Menu_Main(void) {
206203
}
207204
if (res < 0) {
208205
promptError("IOSUHAX_Open failed.");
206+
unmount_sd_fat("sd");
209207
return EXIT_SUCCESS;
210208
}
211209

@@ -214,6 +212,7 @@ int Menu_Main(void) {
214212
int fsaFd = IOSUHAX_FSA_Open();
215213
if (fsaFd < 0) {
216214
promptError("IOSUHAX_FSA_Open failed.");
215+
unmount_sd_fat("sd");
217216
if (mcp_hook_fd >= 0) MCPHookClose();
218217
else IOSUHAX_Close();
219218
return EXIT_SUCCESS;
@@ -226,8 +225,9 @@ int Menu_Main(void) {
226225
ucls();
227226
Title* wiiutitles = loadWiiUTitles();
228227
Title* wiititles = loadWiiTitles();
228+
int* versionList = (int*)malloc(0x100*sizeof(int));
229229

230-
while(1) {
230+
while(wiiutitles!=NULL && wiititles!=NULL) {
231231

232232
OSScreenClearBufferEx(0, 0);
233233
OSScreenClearBufferEx(1, 0);
@@ -237,29 +237,46 @@ int Menu_Main(void) {
237237

238238
Title* titles = mode ? wiititles : wiiutitles;
239239
int count = mode ? titlesvwii : titleswiiu;
240+
int entrycount = 0;
240241

241242
switch(menu) {
242243
case 0: { // Main Menu
244+
entrycount = 2;
243245
console_print_pos(0, 2, " Wii U Save Management");
244246
console_print_pos(0, 3, " vWii Save Management");
245247
console_print_pos(0, 2 + cursor, "->");
246248
} break;
247-
case 1: { // WiiU/vWii Save Management
248-
console_print_pos(0, 2, " Backup savedata");
249-
console_print_pos(0, 3, " Restore savedata");
250-
// console_print_pos(0, 4, " Wipe savedata");
251-
console_print_pos(0, 2 + cursor, "->");
252-
} break;
253-
case 2: { // Wii/Wii U Title List
249+
case 1: { // Select Title
250+
entrycount = count;
254251
for (int i = 0; i < 14; i++) {
255252
if (i+scroll<0 || i+scroll>=count) break;
256-
if (strlen(titles[i+scroll].shortname)) console_print_pos(0, i+2, " %s", titles[i+scroll].shortname);
253+
if (strlen(titles[i+scroll].shortName)) console_print_pos(0, i+2, " %s", titles[i+scroll].shortName);
257254
else console_print_pos(0, i+2, " %08lx%08lx", titles[i+scroll].highID, titles[i+scroll].lowID);
258255
} console_print_pos(0, 2 + cursor, "->");
259256
} break;
260-
case 3: { // Slot select
261-
console_print_pos(0, 2, "Press LEFT or RIGHT to select slot.");
262-
console_print_pos(0, 3, " < %03u >", slot);
257+
case 2: { // Select Task
258+
entrycount = 3 + 2*(mode==0);
259+
console_print_pos(0, 2, " Backup savedata");
260+
console_print_pos(0, 3, " Restore savedata");
261+
console_print_pos(0, 4, " Wipe savedata");
262+
if (mode==0) {
263+
console_print_pos(0, 5, " Import from loadiine");
264+
console_print_pos(0, 6, " Export to loadiine");
265+
}
266+
console_print_pos(0, 2 + cursor, "->");
267+
} break;
268+
case 3: { // Select Options
269+
entrycount = 1 + 2*(mode==0);
270+
console_print_pos(0, 2, "Select %s:", task>2 ? "version" : "slot");
271+
if (task > 2) console_print_pos(0, 3, " < v%u >", versionList ? versionList[slot] : 0);
272+
else console_print_pos(0, 3, " < %03u >", slot);
273+
if (mode==0) {
274+
console_print_pos(0, 5, "Select user:");
275+
console_print_pos(0, 6, " < %s >", (allusers&&(task<3)) ? "all users" : "this user");
276+
console_print_pos(0, 8, "Include 'common' save?");
277+
console_print_pos(0, 9, " < %s >", common ? "yes" : "no ");
278+
console_print_pos(0, 3 + cursor*3, "->");
279+
}
263280
} break;
264281
}
265282

@@ -272,8 +289,6 @@ int Menu_Main(void) {
272289
updatePressedButtons();
273290
updateHeldButtons();
274291

275-
int entrycount = ((menu==0) ? 2 : ((menu==1) ? 2 : count));
276-
277292
if (isPressed(VPAD_BUTTON_DOWN) || isHeld(VPAD_BUTTON_DOWN)) {
278293
if (entrycount<=14) cursor = (cursor + 1) % entrycount;
279294
else if (cursor < 6) cursor++;
@@ -289,31 +304,53 @@ int Menu_Main(void) {
289304
}
290305

291306
if (isPressed(VPAD_BUTTON_LEFT) || isHeld(VPAD_BUTTON_LEFT)) {
292-
if (menu==3) slot--;
307+
if (menu==3) {
308+
switch(cursor) {
309+
case 0: slot--; break;
310+
case 1: allusers^=1; break;
311+
case 2: common^=1; break;
312+
}
313+
}
293314
usleep(100000);
294315
} else if (isPressed(VPAD_BUTTON_RIGHT) || isHeld(VPAD_BUTTON_RIGHT)) {
295-
if (menu==3) slot++;
316+
if (menu==3) {
317+
switch(cursor) {
318+
case 0: slot++; break;
319+
case 1: allusers^=1; break;
320+
case 2: common^=1; break;
321+
}
322+
}
296323
usleep(100000);
297324
}
298325

299326
if (isPressed(VPAD_BUTTON_A)) {
300327
ucls();
301328
if (menu<3) {
302329
if (menu==0) mode = cursor;
303-
if (menu==1) task = cursor;
304-
if (menu==2) targ = cursor+scroll;
330+
if (menu==1) targ = cursor+scroll;
331+
if (menu==2) {
332+
task = cursor;
333+
if (task > 2) {
334+
char gamePath[PATH_SIZE];
335+
memset(versionList, 0, 0x100*sizeof(int));
336+
if (getLoadiineGameSaveDir(gamePath, titles[targ].productCode)==0)
337+
getLoadiineSaveVersionList(versionList, gamePath);
338+
}
339+
}
305340
menu++;
306341
cursor = scroll = 0;
307342
} else {
308343
switch(task) {
309-
case 0: backupSavedata(titles[targ].highID, titles[targ].lowID, titles[targ].isTitleOnUSB, slot); break;
310-
case 1: restoreSavedata(titles[targ].highID, titles[targ].lowID, titles[targ].isTitleOnUSB, slot); break;
311-
case 2: wipeSavedata(titles[targ].highID, titles[targ].lowID, titles[targ].isTitleOnUSB); break;
344+
case 0: backupSavedata(&titles[targ], slot, allusers, common); break;
345+
case 1: restoreSavedata(&titles[targ], slot, allusers, common); break;
346+
case 2: wipeSavedata(&titles[targ], allusers, common); break;
347+
case 3: importFromLoadiine(&titles[targ], common, versionList ? versionList[slot] : 0); break;
348+
case 4: exportToLoadiine(&titles[targ], common, versionList ? versionList[slot] : 0); break;
312349
}
313350
}
314-
} else if (isPressed(VPAD_BUTTON_B)) {
351+
} else if (isPressed(VPAD_BUTTON_B) && menu>0) {
315352
ucls();
316-
if (menu>0) menu--;
353+
menu--;
317354
cursor = scroll = 0;
318355
}
319356

@@ -323,6 +360,7 @@ int Menu_Main(void) {
323360

324361
unloadTitles(wiiutitles);
325362
unloadTitles(wiititles);
363+
free(versionList);
326364

327365
fatUnmount("sd");
328366
fatUnmount("usb");

0 commit comments

Comments
 (0)