-DML view now can see games on usb too

-added possibility to copy gamecube games from
usb to sd card, after copy process game will be 
started (copy takes 5-10 minutes) (issue 12)
-added possibility to install gamecube games
to usb fat partitions
-fixed game name not displayed in delete game dialog
-changed naming scheme of partition name in top-right
corner in coverflow, now looks like DML [USB1], name
depends on view
This commit is contained in:
fix94.1 2012-02-27 16:05:10 +00:00
parent fa7da0a437
commit f1d0386b3c
14 changed files with 454 additions and 39 deletions

268
source/gc/fileOps.c Normal file
View File

@ -0,0 +1,268 @@
/*////////////////////////////////////////////////////////////////////////////////////////
fsop contains coomprensive set of function for file and folder handling
en exposed s_fsop fsop structure can be used by callback to update operation status
////////////////////////////////////////////////////////////////////////////////////////*/
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <math.h>
#include <ogcsys.h>
#include <ogc/lwp_watchdog.h>
#include <dirent.h>
#include <unistd.h>
#include <sys/stat.h> //for mkdir
#include <sys/statvfs.h>
#include "fileOps.h"
#include "memory/mem2.hpp"
#include "utils.h"
s_fsop fsop;
// return false if the file doesn't exist
bool fsop_GetFileSizeBytes (char *path, size_t *filesize) // for me stats st_size report always 0 :(
{
FILE *f;
size_t size = 0;
f = fopen(path, "rb");
if (!f)
{
if (filesize) *filesize = size;
return false;
}
//Get file size
fseek( f, 0, SEEK_END);
size = ftell(f);
if (filesize) *filesize = size;
SAFE_CLOSE(f);
return true;
}
/*
Recursive fsop_GetFolderBytes
*/
u64 fsop_GetFolderBytes (char *source)
{
DIR *pdir;
struct dirent *pent;
char newSource[300];
u64 bytes = 0;
pdir=opendir(source);
while ((pent=readdir(pdir)) != NULL)
{
// Skip it
if (strcmp (pent->d_name, ".") == 0 || strcmp (pent->d_name, "..") == 0)
continue;
sprintf (newSource, "%s/%s", source, pent->d_name);
// If it is a folder... recurse...
if (fsop_DirExist (newSource))
{
bytes += fsop_GetFolderBytes (newSource);
}
else // It is a file !
{
size_t s;
fsop_GetFileSizeBytes (newSource, &s);
bytes += s;
}
}
closedir(pdir);
//Debug ("fsop_GetFolderBytes (%s) = %llu", source, bytes);
return bytes;
}
u32 fsop_GetFolderKb (char *source)
{
u32 ret = (u32) round ((double)fsop_GetFolderBytes (source) / 1000.0);
return ret;
}
u32 fsop_GetFreeSpaceKb (char *path) // Return free kb on the device passed
{
struct statvfs s;
statvfs (path, &s);
u32 ret = (u32)round( ((double)s.f_bfree / 1000.0) * s.f_bsize);
return ret ;
}
bool fsop_DirExist (char *path)
{
DIR *dir;
dir=opendir(path);
if (dir)
{
closedir(dir);
return true;
}
return false;
}
bool fsop_CopyFile (char *source, char *target, progress_callback_t spinner, void *spinner_data)
{
int err = 0;
fsop.breakop = 0;
u8 *buff = NULL;
u32 size;
u32 bytes, rb,wb;
u32 block = 71680; //70KB
FILE *fs = NULL, *ft = NULL;
fs = fopen(source, "rb");
if (!fs)
{
return false;
}
ft = fopen(target, "wt");
if (!ft)
{
SAFE_CLOSE(fs);
return false;
}
//Get file size
fseek (fs, 0, SEEK_END);
size = ftell(fs);
fsop.size = size;
if (size == 0)
{
SAFE_CLOSE(fs);
SAFE_CLOSE(ft);
return true;
}
// Return to beginning....
fseek(fs, 0, SEEK_SET);
buff = MEM2_alloc(block);
if (buff == NULL)
{
SAFE_CLOSE(fs);
return false;
}
bytes = 0;
bool spinnerFlag = false;
if (strstr (source, "game.iso")) {
spinner(bytes, size, spinner_data);
spinnerFlag = true;
}
do
{
rb = fread(buff, 1, block, fs);
wb = fwrite(buff, 1, rb, ft);
if (wb != wb) err = 1;
if (rb == 0) err = 1;
bytes += rb;
if (spinnerFlag) spinner(bytes, size, spinner_data);
fsop.multy.bytes += rb;
fsop.bytes = bytes;
if (fsop.breakop) break;
}
while (bytes < size && err == 0);
SAFE_CLOSE(fs);
SAFE_CLOSE(ft);
MEM2_free(buff);
if (err) unlink (target);
if (fsop.breakop || err) return false;
return true;
}
/*
Semplified folder make
*/
int fsop_MakeFolder (char *path)
{
if (mkdir(path, S_IREAD | S_IWRITE) == 0) return true;
return false;
}
/*
Recursive copyfolder
*/
static bool doCopyFolder (char *source, char *target, progress_callback_t spinner, void *spinner_data)
{
DIR *pdir;
struct dirent *pent;
char newSource[300], newTarget[300];
bool ret = true;
// If target folder doesn't exist, create it !
if (!fsop_DirExist (target))
{
fsop_MakeFolder (target);
}
pdir=opendir(source);
while ((pent=readdir(pdir)) != NULL && ret == true)
{
// Skip it
if (strcmp (pent->d_name, ".") == 0 || strcmp (pent->d_name, "..") == 0)
continue;
sprintf (newSource, "%s/%s", source, pent->d_name);
sprintf (newTarget, "%s/%s", target, pent->d_name);
// If it is a folder... recurse...
if (fsop_DirExist (newSource))
{
ret = doCopyFolder (newSource, newTarget, spinner, spinner_data);
}
else // It is a file !
{
strcpy (fsop.op, pent->d_name);
ret = fsop_CopyFile (newSource, newTarget, spinner, spinner_data);
}
}
closedir(pdir);
return ret;
}
bool fsop_CopyFolder (char *source, char *target, progress_callback_t spinner, void *spinner_data)
{
fsop.breakop = 0;
fsop.multy.startms = ticks_to_millisecs(gettime());
fsop.multy.bytes = 0;
fsop.multy.size = fsop_GetFolderBytes (source);
return doCopyFolder (source, target, spinner, spinner_data);
}

46
source/gc/fileOps.h Normal file
View File

@ -0,0 +1,46 @@
#ifdef __cplusplus
extern "C"
{
#endif
#ifndef _FILEOPS
#define _FILEOPS
typedef void (*progress_callback_t)(int status,int total,void *user_data);
typedef struct
{
u64 size, bytes; // for operation that uses more than one file
u32 startms;
}
s_fsopmulty;
typedef struct
{
char op[256]; // Calling process can set filename or any other info that fit
u32 size, bytes;
s_fsopmulty multy;
int flag1; // user defined flag
bool breakop; // allow to stop a long operation
}
s_fsop;
extern s_fsop fsop;
bool fsop_GetFileSizeBytes (char *path, size_t *filesize);
u64 fsop_GetFolderBytes (char *source);
u32 fsop_GetFolderKb (char *source);
u32 fsop_GetFreeSpaceKb (char *path);
bool fsop_DirExist (char *path);
bool fsop_CopyFile (char *source, char *target, progress_callback_t spinner, void *spinner_data);
int fsop_MakeFolder (char *path);
bool fsop_CopyFolder (char *source, char *target, progress_callback_t spinner, void *spinner_data);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -4,6 +4,7 @@
#include <dirent.h> #include <dirent.h>
#include "gc.h" #include "gc.h"
#include "gecko.h" #include "gecko.h"
#include "fileOps.h"
#define MAX_FAT_PATH 1024 #define MAX_FAT_PATH 1024
@ -94,18 +95,18 @@ void set_language(u8 lang)
while(!__SYS_SyncSram()); while(!__SYS_SyncSram());
} }
void DML_RemoveGame(const char *discid) void DML_RemoveGame(const char *discid, const char* partition)
{ {
int num = 6; int num = 6;
const char *fl[6] = {"sd:/games/%s/game.iso","sd:/games/%s/sys/boot.bin","sd:/games/%s/sys/bi2.bin", const char *fl[6] = {"%s:/games/%s/game.iso","%s:/games/%s/sys/boot.bin","%s:/games/%s/sys/bi2.bin",
"sd:/games/%s/sys/apploader.img","sd:/games/%s/sys","sd:/games/%s"}; "%s:/games/%s/sys/apploader.img","%s:/games/%s/sys","%s:/games/%s"};
char fname[MAX_FAT_PATH]; char fname[MAX_FAT_PATH];
FILE *f; FILE *f;
DIR *dir; DIR *dir;
int i; int i;
for(i = 0; i < num; i++) for(i = 0; i < num; i++)
{ {
sprintf(fname, fl[i], discid); sprintf(fname, fl[i], partition, discid);
f = fopen((char*)fname, "r"); f = fopen((char*)fname, "r");
if(f) if(f)
{ {
@ -123,10 +124,10 @@ void DML_RemoveGame(const char *discid)
} }
} }
bool DML_GameIsInstalled(char *discid) bool DML_GameIsInstalled(char *discid, const char* partition)
{ {
char filepath[64]; char filepath[64];
sprintf(filepath, "sd:/games/%s/game.iso", discid); sprintf(filepath, "%s:/games/%s/game.iso", partition, discid);
gprintf("Filepath on SD: %s\n", filepath); gprintf("Filepath on SD: %s\n", filepath);

View File

@ -7,8 +7,8 @@ extern "C"
#define GC_H_ #define GC_H_
void set_video_mode(int i); void set_video_mode(int i);
void set_language(u8 lang); void set_language(u8 lang);
void DML_RemoveGame(const char *discid); void DML_RemoveGame(const char *discid, const char* partition);
bool DML_GameIsInstalled(char *discid); bool DML_GameIsInstalled(char *discid, const char* partition);
#endif //GC_H_ #endif //GC_H_
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -131,7 +131,7 @@ void CList<dir_discHdr>::GetHeaders(safe_vector<string> pathlist, safe_vector<di
if (wbfs || (*itr).rfind(".iso") != string::npos || (*itr).rfind(".ISO") != string::npos) if (wbfs || (*itr).rfind(".iso") != string::npos || (*itr).rfind(".ISO") != string::npos)
{ {
char* filename = &(*itr)[(*itr).find_last_of('/')+1]; char* filename = &(*itr)[(*itr).find_last_of('/')+1];
if(strcasecmp(filename, "game.iso") == 0 && strncasecmp((*itr).c_str(), "sd:/games/", 10) == 0 ) if(strcasecmp(filename, "game.iso") == 0 && strstr((*itr).c_str(), ":/games/") != NULL)
{ {
FILE *fp = fopen((*itr).c_str(), "rb"); FILE *fp = fopen((*itr).c_str(), "rb");
if( fp ) if( fp )

View File

@ -175,12 +175,12 @@ s32 GCDump::DumpGame(progress_callback_t spinner, void *spinner_data)
s32 ret = Disc_ReadGCHeader(&gcheader); s32 ret = Disc_ReadGCHeader(&gcheader);
Asciify2(gcheader.title); Asciify2(gcheader.title);
snprintf(folder, sizeof(folder), "%s:/games/%s [%s]", DeviceName[SD], gcheader.title, (char *)gcheader.id); snprintf(folder, sizeof(folder), "%s:/games/%s [%s]", gamepartition, gcheader.title, (char *)gcheader.id);
makedir((char *)folder); makedir((char *)folder);
if(writeexfiles) if(writeexfiles)
{ {
snprintf(folder, sizeof(folder), "%s:/games/%s [%s]/sys", DeviceName[SD], gcheader.title, (char *)gcheader.id); snprintf(folder, sizeof(folder), "%s:/games/%s [%s]/sys", gamepartition, gcheader.title, (char *)gcheader.id);
makedir((char *)folder); makedir((char *)folder);
} }
@ -240,7 +240,7 @@ s32 GCDump::DumpGame(progress_callback_t spinner, void *spinner_data)
__DiscWrite(gamepath, 0x2440, ApploaderSize, spinner, spinner_data); __DiscWrite(gamepath, 0x2440, ApploaderSize, spinner, spinner_data);
} }
snprintf(gamepath, sizeof(gamepath), "%s:/games/%s [%s]/game.iso", DeviceName[SD], gcheader.title, (char *)gcheader.id); snprintf(gamepath, sizeof(gamepath), "%s:/games/%s [%s]/game.iso", gamepartition, gcheader.title, (char *)gcheader.id);
gprintf("Writing %s\n", gamepath); gprintf("Writing %s\n", gamepath);
if(compressed) if(compressed)
@ -389,6 +389,6 @@ s32 GCDump::CheckSpace(u32 *needed, bool comp)
MEM2_free(FSTBuffer); MEM2_free(FSTBuffer);
} }
*needed = size/0x8000; *needed = size/0x8000;
gprintf("Free space needed on SD: %d bytes (%x blocks)\n", size, size/0x8000); gprintf("Free space needed: %d bytes (%x blocks)\n", size, size/0x8000);
return 0; return 0;
} }

View File

@ -33,7 +33,7 @@ typedef void (*progress_callback_t)(int status,int total,void *user_data);
class GCDump class GCDump
{ {
public: public:
void Init(bool skip, bool comp, bool wexf, bool align, u32 nretry, u32 rsize) void Init(bool skip, bool comp, bool wexf, bool align, u32 nretry, u32 rsize, const char* partition)
{ {
skiponerror = skip; skiponerror = skip;
compressed = comp; compressed = comp;
@ -41,6 +41,7 @@ public:
force_32k_align = align; force_32k_align = align;
gc_nbrretry = nretry; gc_nbrretry = nretry;
gc_readsize = rsize; gc_readsize = rsize;
gamepartition = partition;
gc_skipped = 0; gc_skipped = 0;
} }
s32 DumpGame(progress_callback_t spinner, void *spinner_data); s32 DumpGame(progress_callback_t spinner, void *spinner_data);
@ -50,6 +51,7 @@ private:
bool skiponerror; bool skiponerror;
bool compressed; bool compressed;
bool writeexfiles; bool writeexfiles;
const char* gamepartition;
u32 gc_nbrretry; u32 gc_nbrretry;
u32 gc_error; u32 gc_error;
u32 gc_retry; u32 gc_retry;

View File

@ -135,6 +135,7 @@ CMenu::CMenu(CVideo &vid) :
m_gamesound_changed = false; m_gamesound_changed = false;
m_base_font_size = 0; m_base_font_size = 0;
m_current_view = COVERFLOW_USB; m_current_view = COVERFLOW_USB;
copyGameCubeGame = false;
} }
extern "C" { int makedir(char *newdir); } extern "C" { int makedir(char *newdir); }
@ -1876,12 +1877,13 @@ bool CMenu::_loadHomebrewList()
bool CMenu::_loadDmlList() bool CMenu::_loadDmlList()
{ {
if(!DeviceHandler::Instance()->IsInserted(SD)) currentPartition = m_cfg.getInt("DML", "partition", 0);
if(!DeviceHandler::Instance()->IsInserted(currentPartition))
return false; return false;
gprintf("%s\n", DeviceName[SD]); gprintf("%s\n", DeviceName[currentPartition]);
DeviceHandler::Instance()->Open_WBFS(SD); DeviceHandler::Instance()->Open_WBFS(currentPartition);
m_gameList.Load(sfmt(DML_DIR, DeviceName[SD]), ".iso", m_cfg.getString("DML", "lastlanguage", "EN").c_str()); m_gameList.Load(sfmt(DML_DIR, DeviceName[currentPartition]), ".iso", m_cfg.getString("DML", "lastlanguage", "EN").c_str());
m_cfg.setString("DML", "lastlanguage", m_loc.getString(m_curLanguage, "gametdb_code", "EN")); m_cfg.setString("DML", "lastlanguage", m_loc.getString(m_curLanguage, "gametdb_code", "EN"));
m_cfg.save(); m_cfg.save();
return m_gameList.size() > 0 ? true : false; return m_gameList.size() > 0 ? true : false;

View File

@ -634,6 +634,7 @@ private:
private: private:
enum WBFS_OP { WO_ADD_GAME, WO_REMOVE_GAME, WO_FORMAT }; enum WBFS_OP { WO_ADD_GAME, WO_REMOVE_GAME, WO_FORMAT };
bool copyGameCubeGame;
typedef std::pair<std::string, u32> FontDesc; typedef std::pair<std::string, u32> FontDesc;
typedef std::map<FontDesc, SFont> FontSet; typedef std::map<FontDesc, SFont> FontSet;
typedef std::map<std::string, STexture> TexSet; typedef std::map<std::string, STexture> TexSet;
@ -931,6 +932,7 @@ private:
static void _addDiscProgress(int status, int total, void *user_data); static void _addDiscProgress(int status, int total, void *user_data);
static int _gameInstaller(void *obj); static int _gameInstaller(void *obj);
static int _GCgameInstaller(void *obj); static int _GCgameInstaller(void *obj);
static int _GCcopyGame(void *obj);
wstringEx _optBoolToString(int b); wstringEx _optBoolToString(int b);
void _stopSounds(void); void _stopSounds(void);

View File

@ -84,14 +84,12 @@ void CMenu::_showConfig(void)
_setBg(m_configBg, m_configBg); _setBg(m_configBg, m_configBg);
m_btnMgr.show(m_configLblTitle); m_btnMgr.show(m_configLblTitle);
m_btnMgr.show(m_configBtnBack); m_btnMgr.show(m_configBtnBack);
if (m_current_view != COVERFLOW_DML && !m_locked) if (!m_locked)
{ {
m_btnMgr.show(m_configLblPartitionName); m_btnMgr.show(m_configLblPartitionName);
m_btnMgr.show(m_configLblPartition); m_btnMgr.show(m_configLblPartition);
m_btnMgr.show(m_configBtnPartitionP); m_btnMgr.show(m_configBtnPartitionP);
m_btnMgr.show(m_configBtnPartitionM); m_btnMgr.show(m_configBtnPartitionM);
}
if (!m_locked) {
m_btnMgr.show(m_configLblDownload); m_btnMgr.show(m_configLblDownload);
m_btnMgr.show(m_configBtnDownload); m_btnMgr.show(m_configBtnDownload);
} }

View File

@ -161,8 +161,6 @@ void CMenu::_showGameSettings(void)
if(m_current_view != COVERFLOW_DML) if(m_current_view != COVERFLOW_DML)
{ {
m_btnMgr.hide(m_gameSettingsBtnCategoryMain); m_btnMgr.hide(m_gameSettingsBtnCategoryMain);
m_btnMgr.hide(m_gameSettingsLblCategoryMain); m_btnMgr.hide(m_gameSettingsLblCategoryMain);

View File

@ -424,6 +424,19 @@ void CMenu::_game(bool launch)
else if (launch || m_btnMgr.selected(m_gameBtnPlay) || (!WPadIR_Valid(0) && !WPadIR_Valid(1) && !WPadIR_Valid(2) && !WPadIR_Valid(3) && m_btnMgr.selected((u32)-1))) else if (launch || m_btnMgr.selected(m_gameBtnPlay) || (!WPadIR_Valid(0) && !WPadIR_Valid(1) && !WPadIR_Valid(2) && !WPadIR_Valid(3) && m_btnMgr.selected((u32)-1)))
{ {
_hideGame(); _hideGame();
if(currentPartition != SD && m_current_view == COVERFLOW_DML)
{
copyGameCubeGame = true;
if(!_wbfsOp(CMenu::WO_ADD_GAME))
{
copyGameCubeGame = false;
break;
}
currentPartition = SD;
}
copyGameCubeGame = false;
dir_discHdr *hdr = m_cf.getHdr(); dir_discHdr *hdr = m_cf.getHdr();
m_cf.clear(); m_cf.clear();

View File

@ -156,13 +156,15 @@ void CMenu::LoadView(void)
m_cf.applySettings(); m_cf.applySettings();
char *mode = (m_current_view == COVERFLOW_CHANNEL && m_cfg.getBool("NAND", "disable", true)) char *mode = (m_current_view == COVERFLOW_CHANNEL && m_cfg.getBool("NAND", "disable", true))
? (char *)"NAND" : ((m_current_view == COVERFLOW_DML) ? (char *)"DML" : (char *)DeviceName[currentPartition]); ? (char *)"NAND" : (char *)DeviceName[currentPartition];
for(u8 i = 0; strncmp((const char *)&mode[i], "\0", 1) != 0; i++) for(u8 i = 0; strncmp((const char *)&mode[i], "\0", 1) != 0; i++)
mode[i] = toupper(mode[i]); mode[i] = toupper(mode[i]);
m_showtimer=60; m_showtimer=60;
m_btnMgr.setText(m_mainLblNotice, (string)mode); char gui_name[20];
sprintf(gui_name,"%s [%s]",_domainFromView(),mode);
m_btnMgr.setText(m_mainLblNotice, (string)gui_name);
m_btnMgr.show(m_mainLblNotice); m_btnMgr.show(m_mainLblNotice);
} }
@ -370,7 +372,7 @@ int CMenu::main(void)
{ {
bool block = m_current_view == COVERFLOW_CHANNEL && m_cfg.getBool("NAND", "disable", true); bool block = m_current_view == COVERFLOW_CHANNEL && m_cfg.getBool("NAND", "disable", true);
char *partition; char *partition;
if(!block && (m_current_view != COVERFLOW_DML)) if(!block)
{ {
_showWaitMessage(); _showWaitMessage();
_hideMain(); _hideMain();
@ -387,7 +389,7 @@ int CMenu::main(void)
(m_current_view == COVERFLOW_CHANNEL && (DeviceHandler::Instance()->GetFSType(currentPartition) != PART_FS_FAT || (m_current_view == COVERFLOW_CHANNEL && (DeviceHandler::Instance()->GetFSType(currentPartition) != PART_FS_FAT ||
(!isD2XnewerThanV6 && DeviceHandler::Instance()->PathToDriveType(m_appDir.c_str()) == currentPartition) || (!isD2XnewerThanV6 && DeviceHandler::Instance()->PathToDriveType(m_appDir.c_str()) == currentPartition) ||
(!isD2XnewerThanV6 && DeviceHandler::Instance()->PathToDriveType(m_dataDir.c_str()) == currentPartition))) || (!isD2XnewerThanV6 && DeviceHandler::Instance()->PathToDriveType(m_dataDir.c_str()) == currentPartition))) ||
(m_current_view == COVERFLOW_HOMEBREW && DeviceHandler::Instance()->GetFSType(currentPartition) == PART_FS_WBFS)) ((m_current_view == COVERFLOW_HOMEBREW || m_current_view == COVERFLOW_DML) && DeviceHandler::Instance()->GetFSType(currentPartition) == PART_FS_WBFS))
{ {
currentPartition = loopNum(currentPartition + 1, (int)USB8); currentPartition = loopNum(currentPartition + 1, (int)USB8);
if(limiter > 10) break; if(limiter > 10) break;
@ -399,8 +401,6 @@ int CMenu::main(void)
m_cfg.setInt(_domainFromView(), "partition", currentPartition); m_cfg.setInt(_domainFromView(), "partition", currentPartition);
} }
else if (m_current_view == COVERFLOW_DML)
partition = (char *)"DML";
else else
partition = (char *)"NAND"; partition = (char *)"NAND";
@ -410,10 +410,12 @@ int CMenu::main(void)
gprintf("Next item: %s\n", partition); gprintf("Next item: %s\n", partition);
m_showtimer=60; m_showtimer=60;
m_btnMgr.setText(m_mainLblNotice, (string)partition); char gui_name[20];
sprintf(gui_name,"%s [%s]",_domainFromView(),partition);
m_btnMgr.setText(m_mainLblNotice, (string)gui_name);
m_btnMgr.show(m_mainLblNotice); m_btnMgr.show(m_mainLblNotice);
if(!block && (m_current_view != COVERFLOW_DML)) if(!block)
{ {
_loadList(); _loadList();
_showMain(); _showMain();

View File

@ -4,6 +4,9 @@
#include "lockMutex.hpp" #include "lockMutex.hpp"
#include "loader/gc_disc.hpp" #include "loader/gc_disc.hpp"
#include "gc.h" #include "gc.h"
#include "fileOps.h"
#include "music/SoundHandler.hpp"
#include "channel/nand.hpp"
using namespace std; using namespace std;
@ -119,19 +122,21 @@ int CMenu::_GCgameInstaller(void *obj)
u32 nretry = m.m_cfg.getUInt("DML", "num_retries", 5); u32 nretry = m.m_cfg.getUInt("DML", "num_retries", 5);
u32 rsize = 32768; u32 rsize = 32768;
m_gcdump.Init(skip, comp, wexf, alig, nretry, rsize); m_gcdump.Init(skip, comp, wexf, alig, nretry, rsize,DeviceName[currentPartition]);
int ret; int ret;
if (!DeviceHandler::Instance()->IsInserted(SD)) if (!DeviceHandler::Instance()->IsInserted(currentPartition))
{ {
m.m_thrdWorking = false; m.m_thrdWorking = false;
return -1; return -1;
} }
char partition[strlen(DeviceName[currentPartition])+2];
sprintf(partition,"%s:/",DeviceName[currentPartition]);
struct statvfs stats; struct statvfs stats;
memset(&stats, 0, sizeof(stats)); memset(&stats, 0, sizeof(stats));
statvfs("sd:/" , &stats); statvfs(partition , &stats);
u64 free = (u64)stats.f_frsize * (u64)stats.f_bfree; u64 free = (u64)stats.f_frsize * (u64)stats.f_bfree;
u32 needed = 0; u32 needed = 0;
@ -170,6 +175,45 @@ int CMenu::_GCgameInstaller(void *obj)
return ret; return ret;
} }
int CMenu::_GCcopyGame(void *obj)
{
CMenu &m = *(CMenu *)obj;
char partition[strlen(DeviceName[SD])];
sprintf(partition,"%s:/",DeviceName[SD]);
if(fsop_GetFreeSpaceKb((char*)DeviceName[SD])<fsop_GetFolderKb(m.m_cf.getHdr()->path))
{
LWP_MutexLock(m.m_mutex);
m._setThrdMsg(wfmt(m._fmt("wbfsop11", L"Not enough space: %d blocks needed, %d available"), fsop_GetFolderKb(m.m_cf.getHdr()->path), fsop_GetFreeSpaceKb(partition)), 0.f);
LWP_MutexUnlock(m.m_mutex);
m.m_thrdWorking = false;
return -1;
}
else
{
LWP_MutexLock(m.m_mutex);
m._setThrdMsg(L"", 0);
char folder[10] = "sd:/games";
if (!fsop_DirExist(folder))
{
fsop_MakeFolder(folder);
}
char source[64];
char target[64];
sprintf(source, "%s:/games/%s", DeviceName[currentPartition], m.m_cf.getHdr()->path);
sprintf(target, "sd:/games/%s", m.m_cf.getHdr()->path);
gprintf("Copying from: \n%s \nto: \n%s\n",source,target);
LWP_MutexUnlock(m.m_mutex);
fsop_CopyFolder(source, target, CMenu::_addDiscProgress, obj);
LWP_MutexLock(m.m_mutex);
m._setThrdMsg(m._t("wbfsop12", L"Game copied"), 1.f);
gprintf("Game copied.\n");
LWP_MutexUnlock(m.m_mutex);
slotLight(true);
}
m.m_thrdWorking = false;
return 0;
}
bool CMenu::_wbfsOp(CMenu::WBFS_OP op) bool CMenu::_wbfsOp(CMenu::WBFS_OP op)
{ {
lwp_t thread = 0; lwp_t thread = 0;
@ -188,10 +232,13 @@ bool CMenu::_wbfsOp(CMenu::WBFS_OP op)
switch (op) switch (op)
{ {
case CMenu::WO_ADD_GAME: case CMenu::WO_ADD_GAME:
if(copyGameCubeGame)
m_btnMgr.setText(m_wbfsLblDialog, _t("wbfscpydlg", L"If you are sure you want to copy this game to SD, click on Go."));
else
m_btnMgr.setText(m_wbfsLblDialog, _t("wbfsadddlg", L"Please insert the disc you want to copy, then click on Go.")); m_btnMgr.setText(m_wbfsLblDialog, _t("wbfsadddlg", L"Please insert the disc you want to copy, then click on Go."));
break; break;
case CMenu::WO_REMOVE_GAME: case CMenu::WO_REMOVE_GAME:
m_btnMgr.setText(m_wbfsLblDialog, wfmt(_fmt("wbfsremdlg", L"To permanently remove the game : %s, click on Go."), m_cf.getTitle().c_str())); m_btnMgr.setText(m_wbfsLblDialog, wfmt(_fmt("wbfsremdlg", L"To permanently remove the game: %s, click on Go."), (u8*)m_cf.getTitle().toUTF8().c_str()));
break; break;
case CMenu::WO_FORMAT: case CMenu::WO_FORMAT:
break; break;
@ -202,7 +249,11 @@ bool CMenu::_wbfsOp(CMenu::WBFS_OP op)
{ {
_mainLoopCommon(false, m_thrdWorking); _mainLoopCommon(false, m_thrdWorking);
if ((BTN_HOME_PRESSED || BTN_B_PRESSED) && !m_thrdWorking) if ((BTN_HOME_PRESSED || BTN_B_PRESSED) && !m_thrdWorking)
{
if (copyGameCubeGame)
return done;
break; break;
}
else if (BTN_UP_PRESSED) else if (BTN_UP_PRESSED)
m_btnMgr.up(); m_btnMgr.up();
else if (BTN_DOWN_PRESSED) else if (BTN_DOWN_PRESSED)
@ -210,7 +261,11 @@ bool CMenu::_wbfsOp(CMenu::WBFS_OP op)
if (BTN_A_PRESSED && !m_thrdWorking) if (BTN_A_PRESSED && !m_thrdWorking)
{ {
if (m_btnMgr.selected(m_wbfsBtnBack)) if (m_btnMgr.selected(m_wbfsBtnBack))
{
if (copyGameCubeGame)
return done;
break; break;
}
else if (m_btnMgr.selected(m_wbfsBtnGo)) else if (m_btnMgr.selected(m_wbfsBtnGo))
{ {
switch (op) switch (op)
@ -222,6 +277,34 @@ bool CMenu::_wbfsOp(CMenu::WBFS_OP op)
m_btnMgr.hide(m_wbfsBtnBack); m_btnMgr.hide(m_wbfsBtnBack);
m_btnMgr.show(m_wbfsLblMessage); m_btnMgr.show(m_wbfsLblMessage);
m_btnMgr.setText(m_wbfsLblMessage, L""); m_btnMgr.setText(m_wbfsLblMessage, L"");
if (copyGameCubeGame)
{
char gcfolder[64];
char* title = (char *)m_cf.getTitle().toUTF8().c_str();
char* gameid = (char *)m_cf.getHdr()->hdr.id;
sprintf(gcfolder, "%s [%s]", title, gameid);
if (DML_GameIsInstalled(gameid, DeviceName[SD]) || DML_GameIsInstalled(gcfolder, DeviceName[SD]))
{
error(_t("wbfsoperr4", L"Game already installed"));
out = true;
break;
}
cfPos = string(gameid);
m_btnMgr.setText(m_wbfsLblDialog, wfmt(_fmt("wbfsop10", L"Copying [%s] %s..."), (u8*)gameid, (u8*)m_cf.getTitle().toUTF8().c_str()));
done = true;
m_thrdWorking = true;
m_thrdProgress = 0.f;
m_thrdMessageAdded = false;
m_cf.stopCoverLoader();
_stopSounds();
MusicPlayer::DestroyInstance();
SoundHandler::DestroyInstance();
soundDeinit();
Nand::Instance()->Disable_Emu();
Nand::DestroyInstance();
LWP_CreateThread(&thread, (void *(*)(void *))CMenu::_GCcopyGame, (void *)this, 0, 8 * 1024, 64);
break;
}
Disc_SetUSB(NULL); Disc_SetUSB(NULL);
if (Disc_Wait() < 0) if (Disc_Wait() < 0)
{ {
@ -260,7 +343,7 @@ bool CMenu::_wbfsOp(CMenu::WBFS_OP op)
char gcfolder[64]; char gcfolder[64];
sprintf(gcfolder, "%s [%s]", gcheader.title, (char *)gcheader.id); sprintf(gcfolder, "%s [%s]", gcheader.title, (char *)gcheader.id);
if (_searchGamesByID((const char *) gcheader.id).size() != 0 || DML_GameIsInstalled((char *)gcheader.id) || DML_GameIsInstalled(gcfolder)) if (_searchGamesByID((const char *) gcheader.id).size() != 0 || DML_GameIsInstalled((char *)gcheader.id, DeviceName[currentPartition]) || DML_GameIsInstalled(gcfolder, DeviceName[currentPartition]))
{ {
error(_t("wbfsoperr4", L"Game already installed")); error(_t("wbfsoperr4", L"Game already installed"));
out = true; out = true;
@ -286,7 +369,7 @@ bool CMenu::_wbfsOp(CMenu::WBFS_OP op)
if(m_current_view == COVERFLOW_USB) if(m_current_view == COVERFLOW_USB)
WBFS_RemoveGame((u8 *)m_cf.getId().c_str(), (char *) m_cf.getHdr()->path); WBFS_RemoveGame((u8 *)m_cf.getId().c_str(), (char *) m_cf.getHdr()->path);
else else
DML_RemoveGame(m_cf.getHdr()->path); DML_RemoveGame(m_cf.getHdr()->path, DeviceName[currentPartition]);
if(m_cfg.getBool("GENERAL", "delete_cover_and_game", true)) if(m_cfg.getBool("GENERAL", "delete_cover_and_game", true))
RemoveCover((char *)m_cf.getId().c_str()); RemoveCover((char *)m_cf.getId().c_str());
m_btnMgr.show(m_wbfsPBar); m_btnMgr.show(m_wbfsPBar);
@ -319,7 +402,7 @@ bool CMenu::_wbfsOp(CMenu::WBFS_OP op)
} }
} }
_hideWBFS(); _hideWBFS();
if (done && (op == CMenu::WO_REMOVE_GAME || op == CMenu::WO_ADD_GAME)) if (done && !copyGameCubeGame && (op == CMenu::WO_REMOVE_GAME || op == CMenu::WO_ADD_GAME))
{ {
m_gameList.SetLanguage(m_loc.getString(m_curLanguage, "gametdb_code", "EN").c_str()); m_gameList.SetLanguage(m_loc.getString(m_curLanguage, "gametdb_code", "EN").c_str());
if( upd_dml ) if( upd_dml )