Added folder and alphatebital sorting support by dragonbane0.

This commit is contained in:
suloku
2017-04-05 01:16:46 +02:00
parent 75a5e024b7
commit 7133bf399d
6 changed files with 328 additions and 99 deletions

View File

@@ -2,8 +2,8 @@
<app version="1">
<name>GCMM</name>
<coder>Suloku</coder>
<version>1.4e</version>
<release_date>20160217000000</release_date>
<version>1.4f</version>
<release_date>20170505000000</release_date>
<short_description>Memory Card Manager</short_description>
<long_description>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.</long_description>

View File

@@ -1,5 +1,5 @@
ח<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>-<2D><><EFBFBD><EFBFBD>-<2D><><EFBFBD>
|0O<30><4F>o<EFBFBD> GCMM 1.4e by suloku <20>o<EFBFBD><6F>O0|
|0O<30><4F>o<EFBFBD> GCMM 1.4f by suloku <20>o<EFBFBD><6F>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<30><4F>o<EFBFBD> UPDATE HISTORY <20>o<EFBFBD><6F>O0|
`<60><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>'
[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.

View File

@@ -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 ++;

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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;