diff --git a/hbc/meta.xml b/hbc/meta.xml index db92f4a..e81bbd6 100644 --- a/hbc/meta.xml +++ b/hbc/meta.xml @@ -2,8 +2,8 @@ GCMM Suloku - 1.4e - 20160217000000 + 1.4f + 20170505000000 Memory Card Manager A memory card manager for Wii/GC. @@ -11,6 +11,7 @@ Updated to latest libraries by PabloACZ Batch gci backup by Pikachu025 Banner and Icon support by dronesplitter F-Zero and Phantasy Star Online support by Ralf +Folder and sorting support by dragonbane0 Thanks to original mcbackup example code, Askot, dsbomb and justb. Special thanks to Costis, Masken, Tantric and tueidj. diff --git a/readme.txt b/readme.txt index 2508904..ef2bd84 100644 --- a/readme.txt +++ b/readme.txt @@ -1,5 +1,5 @@ ח–­—–­—–­—–­ –­—–­—–­—–­—–­—–­—–­—–­—–­—–­— ­—–­—–­—–­—–­—–­—–­—–­—-­—–­-–•Ĵ -|0O×ĝo· GCMM 1.4e by suloku ·oĝ×O0| +|0O×ĝo· GCMM 1.4f by suloku ·oĝ×O0| | https://github.com/suloku/gcmm | | (old site: http://code.google.com/p/gcmm) | | (Under GPL License) | @@ -31,6 +31,9 @@ I (suloku) have updated the code to newest libraries to port it to the Wii syste |0O×ĝo· UPDATE HISTORY ·oĝ×O0| `¨•¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨' +[What's New 1.4f - april 05, 2017 - By suloku] +* dragonbane0 made a mod of version 1.4c with folder selection and alphabetical sorting. Zephiles pointed this out and the changes have been merged. Thanks you both! + [What's New 1.4e - february 27, 2016 - By suloku] * Fixed bug in card.c that prevented correct backup/write of saves with same filename but different case. Bug affected Timesplitters 2, probably Timesplitters 3 too. Thanks to DakuTree for reporting and Antidote for fixing. diff --git a/source/freetype.c b/source/freetype.c index 73c0183..2654ff7 100644 --- a/source/freetype.c +++ b/source/freetype.c @@ -81,6 +81,9 @@ extern GCI gci; extern u8 FileBuffer[MAXFILEBUFFER] ATTRIBUTE_ALIGN (32); extern u8 CommentBuffer[64] ATTRIBUTE_ALIGN (32); +extern u8 currFolder[260]; +extern int folderCount; + #define PAGESIZE 16 @@ -816,6 +819,7 @@ void showSaveInfo(int sel) { int y = 165, x = 378, j; char gamecode[5], company[3], txt[1024]; + int isFolder = 0; //clear right pane, but just the save info int bgcolor = getcolour(84,174,211); @@ -829,12 +833,23 @@ void showSaveInfo(int sel) // TODO: only read the necessary header + comment, display banner and icon files if (mode == RESTORE_MODE) { - j = SDLoadMCImageHeader((char*)filelist[sel]); - // struct gci now contains header info - memcpy(company, gci.company, 2); - memcpy(gamecode, gci.gamecode, 4); - company[2] = gamecode[4] = 0; - + //Dragonbane: Show basic info if folder + + char folder[1024]; + sprintf (folder, "fat:/%s/%s", currFolder, (char*)filelist[sel]); + + if(isdir_sd(folder) == 1) + { + isFolder = 1; + } + else + { + j = SDLoadMCImageHeader((char*)filelist[sel]); + // struct gci now contains header info + memcpy(company, gci.company, 2); + memcpy(gamecode, gci.gamecode, 4); + company[2] = gamecode[4] = 0; + } } else if( (mode == BACKUP_MODE) | (mode == DELETE_MODE) ) { @@ -848,7 +863,7 @@ void showSaveInfo(int sel) } //Draw nice gradient background for banner and icon - if(SDCARD_GetBannerFmt(gci.banner_fmt) == 1 || SDCARD_GetBannerFmt(gci.banner_fmt) == 2){ + if((isFolder == 0 && SDCARD_GetBannerFmt(gci.banner_fmt) == 1) || (isFolder == 0 && SDCARD_GetBannerFmt(gci.banner_fmt) == 2)){ //Box for icon+banner DrawHLine (410, 410+160, 172, getcolour (255,255,255)); DrawBox (410, 173, 410+160, 173+39, getcolour (255,255,255)); @@ -859,22 +874,42 @@ void showSaveInfo(int sel) //Box for icon DrawHLine (468, 468+42, 172, getcolour (255,255,255)); DrawBox (468, 173, 468+42, 173+39, getcolour (255,255,255)); - DrawHLine (468, 468+42, 174+39, getcolour (255,255,255)); - DrawBoxFilledGradient(468+2, 174, (468+40), (174+37), BLUECOL, PURPLECOL, LOCATION); - } - - //Show banner if there is one - if (SDCARD_GetBannerFmt(gci.banner_fmt) == CARD_BANNER_RGB) { - bannerloadRGB(bannerdata); - } - else if (SDCARD_GetBannerFmt(gci.banner_fmt) == CARD_BANNER_CI) { - bannerloadCI(bannerdataCI, tlutbanner); + DrawHLine (468, 468+42, 174+39, getcolour (255,255,255)); + + if (isFolder == 1) + { + DrawBoxFilled(468+2, 174, (468+40), (174+37), getcolour(255,255,0)); + //DrawBoxFilledGradient(468+2, 174, (468+40), (174+37), getcolour(255,255,0), getcolour(255,255,0), LOCATION); + } + else + { + DrawBoxFilledGradient(468+2, 174, (468+40), (174+37), BLUECOL, PURPLECOL, LOCATION); + } } /*** Display relevant info for this save ***/ - sprintf(txt, "#%d %s/%s", sel, gamecode, company); + + if (isFolder == 1) + sprintf(txt, "#%d Folder: %s", sel, (char*)filelist[sel]); + else + sprintf(txt, "#%d %s/%s", sel, gamecode, company); + DrawText(x, y-4, txt); y += 70; + + + if (isFolder == 1) + return; + + + //Show banner if there is one + if (SDCARD_GetBannerFmt(gci.banner_fmt) == CARD_BANNER_RGB) { + bannerloadRGB(bannerdata); + } + else if (SDCARD_GetBannerFmt(gci.banner_fmt) == CARD_BANNER_CI) { + bannerloadCI(bannerdataCI, tlutbanner); + } + //DrawText(x, y, "File Description:"); //y += 20; @@ -996,6 +1031,13 @@ static void ShowFiles (int offset, int selection, int upordown, int saveinfo) { int w; //int textlen = 22; int textlen = 32; + + + //Dragonbane + char name[1024]; + char folder[1024]; + + //If the filelist offset changed, we have to redraw every entry //This tracks switching "pages" of files in the list if (offsetchanged) { @@ -1014,7 +1056,21 @@ static void ShowFiles (int offset, int selection, int upordown, int saveinfo) { for (i = offset; i < (offset + PAGESIZE) && (i < maxfile); ++i){ //changed this to limit characters shown in filename since display gets weird //if we let the entire filename appear - strncpy (text, (char*)filelist[i], textlen); + + sprintf (folder, "fat:/%s/%s", currFolder, (char*)filelist[i]); + + + if(isdir_sd(folder) == 1) + { + sprintf(name, "[Folder]%s", (char*)filelist[i]); + } + else + { + sprintf(name, "%s", (char*)filelist[i]); + } + + + strncpy (text, name, textlen); text[textlen] = 0; if (j == (selection - offset)){ /*** Highlighted text entry ***/ @@ -1051,8 +1107,20 @@ static void ShowFiles (int offset, int selection, int upordown, int saveinfo) { ypos = (screenheight - (PAGESIZE * 20+40)) >> 1; ypos += 26; setfontcolour (0xff, 0xff, 0xff); + //user just pressed up, down, left or right, upordown holds the correction needded - strncpy (text, (char*)filelist[selection+upordown], textlen); + sprintf (folder, "fat:/%s/%s", currFolder, (char*)filelist[selection+upordown]); + + if(isdir_sd(folder) == 1) + { + sprintf(name, "[Folder]%s", (char*)filelist[selection+upordown]); + } + else + { + sprintf(name, "%s", (char*)filelist[selection+upordown]); + } + + strncpy (text, name, textlen); text[textlen] = 0; for (w = 0; w < 20; w++){ DrawLineFast (35, 330, (((selection-offset)+upordown) * 20) + (ypos - 14) + w, 84, 174,211); @@ -1062,7 +1130,21 @@ static void ShowFiles (int offset, int selection, int upordown, int saveinfo) { //appear faster - without it the highlight box glides too much ShowScreen(); setfontcolour (28, 28, 28); - strncpy (text, (char*)filelist[selection], textlen); + + + sprintf (folder, "fat:/%s/%s", currFolder, (char*)filelist[selection]); + + if(isdir_sd(folder) == 1) + { + sprintf(name, "[Folder]%s", (char*)filelist[selection]); + } + else + { + sprintf(name, "%s", (char*)filelist[selection]); + } + + + strncpy (text, name, textlen); text[textlen] = 0; //the current spot is always highlighted for (w = 0; w < 20; w++){ @@ -1237,6 +1319,12 @@ int ShowSelector (int saveinfo) } currframe = i; #endif + + char folder[1024]; + sprintf (folder, "fat:/%s/%s", currFolder, (char*)filelist[selection]); + + if(isdir_sd(folder) == 0) + { //If there's a real icon show it, if not just wait until next icon frame if ( SDCARD_GetIconFmt(gci.icon_fmt,iconindex[currframe])== 1) { //CI with shared palette @@ -1248,6 +1336,8 @@ int ShowSelector (int saveinfo) else if ( SDCARD_GetIconFmt(gci.icon_fmt,iconindex[currframe])== 2) { iconloadRGB(icondataRGB[iconindex[currframe]]); } + } + ShowScreen(); currframe ++; diff --git a/source/main.c b/source/main.c index 74cf5e7..35642f6 100644 --- a/source/main.c +++ b/source/main.c @@ -38,7 +38,7 @@ //Comment FLASHIDCHECK to allow writing any image to any mc. This will corrupt official cards. #define FLASHIDCHECK -const char appversion[] = "v1.4e"; +const char appversion[] = "v1.4f"; int mode; int cancel; int doall; @@ -53,6 +53,8 @@ u32 retraceCount; extern u8 filelist[1024][1024]; extern bool offsetchanged; +extern u8 currFolder[260]; +extern int folderCount; s32 MEM_CARD = CARD_SLOTB; extern syssramex *sramex; @@ -468,16 +470,19 @@ void SD_RestoreMode () int files; int selected; char buffer[256], text[64]; + int inProgress = 1; clearRightPane(); DrawText(380,130,"R e s t o r e M o d e"); DrawText(380,134,"______________________"); - writeStatusBar("Reading files... ", ""); + writeStatusBar("Reading files... ", ""); + + //Dragonbane: Curr Folder to default + + sprintf((char*)currFolder, "MCBACKUP"); files = SDGetFileList (1); - setfontsize (14); - writeStatusBar("Pick a file using UP or DOWN", "Press A to restore to Memory Card ") ; #ifdef HW_RVL DrawText(40, 60, "Press R/1 to restore ALL savegames"); #else @@ -490,75 +495,131 @@ void SD_RestoreMode () } else { - selected = ShowSelector (1); + while(inProgress == 1) + { + setfontsize (14); + writeStatusBar("Pick a file using UP or DOWN", "Press A to restore to Memory Card ") ; + + //It will wait here until user selected a file + selected = ShowSelector (1); - if (cancel) - { - WaitPrompt ("Restore action cancelled !"); - return; - } - else if (doall) - { - doall = WaitPromptChoice("Are you sure you want to restore -ALL- files?", "Yes", "No"); - if (!doall) - { - //Restore All files - for ( selected = 0; selected < files; selected++ ) { - /*** Restore files ***/ - sprintf(buffer, "[%d/%d] Reading from FAT device", selected+1, files); - ShowAction(buffer); - if (SDLoadMCImage ((char*)filelist[selected])) - { - sprintf(buffer, "[%d/%d] Saving to MC slot %s", selected+1, files, (MEM_CARD) ? "B" : "A"); - ShowAction(buffer); - if (!CardWriteFile (MEM_CARD)) - { - strncpy(text, (char*)filelist[selected], 32); - text[32]='\0'; - sprintf(buffer, "Error during restore (%s). Continue?", text); - doall = WaitPromptChoice(buffer, "Yes", "No"); - if (doall) - { - WaitPrompt ("Restore action cancelled due to error!"); - return; - } - } - } - else - { - WaitPrompt ("Error reading image"); - return; - } - } - - WaitPrompt("Full card restore done!"); - return; - } - } - else - { - ShowAction ("Reading from FAT device"); - if (SDLoadMCImage ((char*)filelist[selected])) + if (cancel) { - ShowAction ("Updating Memory Card"); - if (CardWriteFile (MEM_CARD)) + if (strcmp((char*)currFolder, "MCBACKUP") == 0) { - WaitPrompt ("Restore Complete"); + WaitPrompt ("Restore action cancelled !"); return; } else { - WaitPrompt ("Error during restore"); - return; + //Go back one folder + char* pos = strrchr( (char*)currFolder, '/' ); + + currFolder[(pos-(char*)currFolder)] = 0; + + files = SDGetFileList (1); + + cancel = 0; + offsetchanged = true; + usleep(300000); + continue; } + } + else if (doall) + { + doall = WaitPromptChoice("Are you sure you want to restore -ALL- files from this folder?", "Yes", "No"); + if (!doall) + { + //Restore All files (from current folder) + for ( selected = folderCount; selected < files; selected++ ) { + /*** Restore files ***/ + sprintf(buffer, "[%d/%d] Reading from FAT device", selected+1, files); + ShowAction(buffer); + if (SDLoadMCImage ((char*)filelist[selected])) + { + sprintf(buffer, "[%d/%d] Saving to MC slot %s", selected+1, files, (MEM_CARD) ? "B" : "A"); + ShowAction(buffer); + if (!CardWriteFile (MEM_CARD)) + { + strncpy(text, (char*)filelist[selected], 32); + text[32]='\0'; + sprintf(buffer, "Error during restore (%s). Continue?", text); + doall = WaitPromptChoice(buffer, "Yes", "No"); + if (doall) + { + WaitPrompt ("Restore action cancelled due to error!"); + return; + } + } + } + else + { + WaitPrompt ("Error reading image"); + return; + } + } + + WaitPrompt("Full card restore done!"); + return; + } + else + { + return; + } } else { - WaitPrompt ("Error reading image"); - return; + //Check if selection is folder + char folder[1024]; + sprintf (folder, "fat:/%s/%s", currFolder, (char*)filelist[selected]); + + if(isdir_sd(folder) == 1) + { + //Enter folder + sprintf((char*)currFolder, "%s/%s", currFolder, (char*)filelist[selected]); + + files = SDGetFileList (1); + if (!files) + { + WaitPrompt("Folder is empty!"); + + //Go back again + char* pos = strrchr( (char*)currFolder, '/' ); + + currFolder[(pos-(char*)currFolder)] = 0; + + files = SDGetFileList (1); + } + + offsetchanged = true; + usleep(300000); + continue; + } + else + { + ShowAction ("Reading from FAT device"); + if (SDLoadMCImage ((char*)filelist[selected])) + { + ShowAction ("Updating Memory Card"); + if (CardWriteFile (MEM_CARD)) + { + WaitPrompt ("Restore Complete"); + return; + } + else + { + WaitPrompt ("Error during restore"); + return; + } + } + else + { + WaitPrompt ("Error reading image"); + return; + } + } } } - } return; } diff --git a/source/mcard.c b/source/mcard.c index 128ebb6..d140445 100644 --- a/source/mcard.c +++ b/source/mcard.c @@ -48,6 +48,8 @@ int lasticon; /*** This matrix will serve as our array of filenames for each file on the card We add 10 to filenamelen since we add on game company info***/ u8 filelist[1024][1024]; +u8 currFolder[260]; +int folderCount; int maxfile; extern int cancel; extern bool offsetchanged; diff --git a/source/sdsupp.c b/source/sdsupp.c index 8803ce1..21f3d20 100644 --- a/source/sdsupp.c +++ b/source/sdsupp.c @@ -47,6 +47,9 @@ extern u32 maxfile; extern GCI gci; extern int OFFSET; +extern u8 currFolder[260]; +extern int folderCount; + bool file_exists(const char * filename) { FILE * file = fopen(filename, "r"); @@ -175,7 +178,7 @@ int SDLoadMCImage(char *sdfilename) /*** Make fullpath filename ***/ //sprintf (filename, "dev0:\\%s\\%s", MCSAVES, sdfilename); - sprintf (filename, "fat:/%s/%s", MCSAVES, sdfilename); + sprintf (filename, "fat:/%s/%s", currFolder, sdfilename); //SDCARD_Init (); @@ -264,7 +267,7 @@ int SDLoadMCImageHeader(char *sdfilename) memset (CommentBuffer, 0, 64); /*** Make fullpath filename ***/ - sprintf (filename, "fat:/%s/%s", MCSAVES, sdfilename); + sprintf (filename, "fat:/%s/%s", currFolder, sdfilename); /*** Open the SD Card file ***/ @@ -510,7 +513,7 @@ int SDLoadCardImageHeader(char *sdfilename) memset (&cardheader, 0, sizeof(Header)); /*** Make fullpath filename ***/ - sprintf (filename, "fat:/%s/%s", MCSAVES, sdfilename); + sprintf (filename, "fat:/%s/%s", currFolder, sdfilename); /*** Open the SD Card file ***/ handle = fopen ( filename , "rb" ); @@ -610,9 +613,37 @@ int SDGetFileList(int mode) int dirtype; //static struct stat filestat; - char filename[1024]; - sprintf (filename, "fat:/%s/", MCSAVES); + int dirCount = 0; + char filename[1024]; + sprintf (filename, "fat:/%s/", currFolder); + + + //Add Folders + if ((dir = opendir(filename)) == NULL) + { + return -1; + } + + while ((dit = readdir(dir)) != NULL) + { + if(strncmp(dit->d_name, ".", 1) != 0 && strncmp(dit->d_name, "..", 2) != 0) + { + sprintf(namefile, "%s%s", filename, dit->d_name); + + if(isdir_sd(namefile) == 1) + { + strcpy((char *)filelist[filecount], dit->d_name); + dirCount++; + filecount++; + } + } + } + + closedir(dir); + + + //Add Files if ((dir = opendir(filename)) == NULL) { return -1; @@ -622,16 +653,10 @@ int SDGetFileList(int mode) { if(strncmp(dit->d_name, ".", 1) != 0 && strncmp(dit->d_name, "..", 2) != 0) { - if (mode){ - if (compare_extension(dit->d_name, ".gci") || compare_extension(dit->d_name, ".sav") || compare_extension(dit->d_name, ".gcs")){ - strcpy((char *)filelist[filecount], dit->d_name); - sprintf(namefile, "%s%s", filename, dit->d_name); - dirtype = ((isdir_sd(namefile) == 1) ? DIRENT_T_DIR : DIRENT_T_FILE); - - filecount++; - } - }else if (!mode){ - if (compare_extension(dit->d_name, ".raw") || compare_extension(dit->d_name, ".gcp") || compare_extension(dit->d_name, ".mci")){ + if (mode) + { + if (compare_extension(dit->d_name, ".gci") || compare_extension(dit->d_name, ".sav") || compare_extension(dit->d_name, ".gcs")) + { strcpy((char *)filelist[filecount], dit->d_name); sprintf(namefile, "%s%s", filename, dit->d_name); dirtype = ((isdir_sd(namefile) == 1) ? DIRENT_T_DIR : DIRENT_T_FILE); @@ -639,8 +664,54 @@ int SDGetFileList(int mode) filecount++; } } + else if (!mode) + { + if (compare_extension(dit->d_name, ".raw") || compare_extension(dit->d_name, ".gcp") || compare_extension(dit->d_name, ".mci")) + { + strcpy((char *)filelist[filecount], dit->d_name); + sprintf(namefile, "%s%s", filename, dit->d_name); + dirtype = ((isdir_sd(namefile) == 1) ? DIRENT_T_DIR : DIRENT_T_FILE); + + filecount++; + } + } + } } + + + //Dragonbane: Sort folders alphabetically + int i=0; + int j=0; + + for (i = 0; i < dirCount; i++) + { + for (j = i+1; j < dirCount; j++) + if (strcmp((char*)filelist[i], (char*)filelist[j]) > 0) + { + char temp[1024]; + + sprintf(temp, "%s", (char*)filelist[i]); + sprintf((char*)filelist[i], "%s", (char*)filelist[j]); + sprintf((char*)filelist[j], "%s", temp); + } + } + + + //Dragonbane: Sort files alphabetically + + for (i = dirCount; i < filecount; i++) + { + for (j = i+1; j < filecount; j++) + if (strcmp((char*)filelist[i], (char*)filelist[j]) > 0) + { + char temp[1024]; + + sprintf(temp, "%s", (char*)filelist[i]); + sprintf((char*)filelist[i], "%s", (char*)filelist[j]); + sprintf((char*)filelist[j], "%s", temp); + } + } /* while(1) { @@ -658,6 +729,7 @@ int SDGetFileList(int mode) closedir(dir); // cierra el directorio maxfile = filecount; + folderCount = dirCount; return filecount; /* int entries = 0;