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
1616u8 slot = 0 ;
17+ bool allusers = 0 , common = 1 ;
1718int menu = 0 , mode = 0 , task = 0 , targ = 0 ;
1819int cursor = 0 , scroll = 0 ;
1920int 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
6053Title * 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
134131Title * 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
194191void 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