* The second disc of a Gamecube game that comes with two discs is now marked as "disc 2" in coverflow

* The GC Ex Dumper will now wait after the first read error so the user can eject the disc to clean it
* Added a check to the GC Ex Dumper that sees if the disc is ejected by accident
* Fixed free block/size calculation for GC Ex Dumper
* Fixed some thread messages
* Again some code cleanup and minor fixes
* Updated dutch.ini
* Updated english.ini

NOTE: The GC Ex dumper will only wait after the first read error. If the disc still contains errors after it's cleaned the dumper will stop the process or continue and lose the unreadable data in "skip on error" mode
This commit is contained in:
overjoy.psm 2012-03-09 02:47:41 +00:00
parent 7891c2d861
commit bf39d8e26a
6 changed files with 150 additions and 58 deletions

View File

@ -133,20 +133,27 @@ void CList<dir_discHdr>::GetHeaders(safe_vector<string> pathlist, safe_vector<di
char* filename = &(*itr)[(*itr).find_last_of('/')+1];
const char* dml_partition = DeviceName[DeviceHandler::Instance()->PathToDriveType((*itr).c_str())];
if(strcasecmp(filename, "game.iso") == 0 && strstr((*itr).c_str(), sfmt((strncmp(dml_partition, "sd", 2) != 0) ? DMLgameUSBDir.c_str() : DML_DIR, dml_partition).c_str()) != NULL)
{
{
FILE *fp = fopen((*itr).c_str(), "rb");
if( fp )
{
fseek( fp, 0x00, SEEK_SET );
fseek( fp, 0, SEEK_SET );
fread( tmp.hdr.id, 1, 6, fp );
u8 gc_disc[1];
fread(gc_disc, 1, 1, fp);
GTitle = custom_titles.getString( "TITLES", (const char *) tmp.hdr.id );
int ccolor = custom_titles.getColor( "COVERS", (const char *) tmp.hdr.id, tmp.hdr.casecolor ).intVal();
if( GTitle.size() > 0 || ( gameTDB.IsLoaded() && gameTDB.GetTitle( (char *)tmp.hdr.id, GTitle ) ) )
{
{
mbstowcs( tmp.title, GTitle.c_str(), sizeof(tmp.title) );
Asciify( tmp.title );
if(gc_disc[0])
wcslcat(tmp.title, L" disc 2", sizeof(tmp.title));
tmp.hdr.casecolor = ccolor != 1 ? ccolor : gameTDB.GetCaseColor( (char *)tmp.hdr.id );
if( tmp.hdr.casecolor == 0xffffffff )
tmp.hdr.casecolor = 0;
@ -165,9 +172,12 @@ void CList<dir_discHdr>::GetHeaders(safe_vector<string> pathlist, safe_vector<di
SAFE_CLOSE(fp);
if ( tmp.hdr.gc_magic == 0xc2339f3d )
{
{
mbstowcs( tmp.title, (const char *)tmp.hdr.title, sizeof( tmp.hdr.title ) );
Asciify(tmp.title);
if(gc_disc[0])
wcslcat(tmp.title, L" disc 2", sizeof(tmp.title));
tmp.hdr.casecolor = 0;
(*itr)[(*itr).find_last_of('/')] = 0;
(*itr).assign(&(*itr)[(*itr).find_last_of('/') + 1]);

View File

@ -57,6 +57,16 @@ s32 GCDump::__DiscReadRaw(void *outbuf, u32 offset, u32 length)
WDVD_LowRequestError(&gc_error);
if(gc_error == 0x30200 || gc_error == 0x30201 || gc_error == 0x31100)
{
if(gc_retry >= gc_nbrretry && waitonerror)
{
__WaitForDisc(Disc, 10);
gc_retry = 0;
waitonerror = false;
if(FSTTotal > FSTSize)
message(4, Disc+1, minfo, u_data);
else
message(3, 0, minfo, u_data);
}
if(gc_retry >= gc_nbrretry)
{
if(!skiponerror)
@ -75,6 +85,14 @@ s32 GCDump::__DiscReadRaw(void *outbuf, u32 offset, u32 length)
}
gc_retry++;
}
else if(gc_error == 0x1023a00)
{
__WaitForDisc(Disc, 11);
if(FSTTotal > FSTSize)
message(4, Disc+1, minfo, u_data);
else
message(3, 0, minfo, u_data);
}
else
{
gprintf("Read error(%x) at offset: 0x%08x.\n", gc_error, offset);
@ -92,19 +110,19 @@ s32 GCDump::__DiscReadRaw(void *outbuf, u32 offset, u32 length)
return -1;
}
s32 GCDump::__DiscWrite(char * path, u32 offset, u32 length, u8 *ReadBuffer, progress_callback_t spinner, void *spinner_data)
s32 GCDump::__DiscWrite(char * path, u32 offset, u32 length, u8 *ReadBuffer)
{
gprintf("__DiscWrite(%s, 0x%08x, %x)\n", path, offset, length);
u32 wrote = 0;
FILE *f = fopen(path, "wb");
wrote = __DiscWriteFile(f, offset, length, ReadBuffer, spinner, spinner_data);
wrote = __DiscWriteFile(f, offset, length, ReadBuffer);
SAFE_CLOSE(f);
return wrote;
}
s32 GCDump::__DiscWriteFile(FILE *f, u32 offset, u32 length, u8 *ReadBuffer, progress_callback_t spinner, void *spinner_data)
s32 GCDump::__DiscWriteFile(FILE *f, u32 offset, u32 length, u8 *ReadBuffer)
{
u32 toread = 0;
u32 wrote = 0;
@ -123,23 +141,26 @@ s32 GCDump::__DiscWriteFile(FILE *f, u32 offset, u32 length, u8 *ReadBuffer, pro
length -= toread;
gc_done += toread;
if(spinner)
spinner(gc_done/1024, DiscSizeCalculated, spinner_data);
spinner(gc_done/1024, DiscSizeCalculated, u_data);
}
return wrote;
}
bool GCDump::__WaitForDisc(u8 dsc, char *minfo, u32 msg, message_callback_t message, void *message_data)
bool GCDump::__WaitForDisc(u8 dsc, u32 msg)
{
u8 *ReadBuffer = (u8 *)MEM2_alloc(0x440);
u32 cover = 0;
bool done = false;
*(u32*)0xCD0000C0 |= 0x20;
bool done = false;
while(!done)
{
message( msg, dsc+1, minfo, message_data);
{
message( msg, dsc+1, minfo, u_data);
while(1)
{
*(u32*)0xCD0000C0 |= 0x20;
usleep( 1000000 );
*(u32*)0xCD0000C0 &= ~0x20;
usleep( 1000000 );
WDVD_GetCoverStatus(&cover);
if(!(cover & 0x2))
break;
@ -147,6 +168,10 @@ bool GCDump::__WaitForDisc(u8 dsc, char *minfo, u32 msg, message_callback_t mess
while(1)
{
*(u32*)0xCD0000C0 |= 0x20;
usleep( 1000000 );
*(u32*)0xCD0000C0 &= ~0x20;
usleep( 1000000 );
if(Disc_Wait() < 0)
continue;
@ -169,33 +194,32 @@ bool GCDump::__WaitForDisc(u8 dsc, char *minfo, u32 msg, message_callback_t mess
Disc2 = *(vu8*)(ReadBuffer+0x06);
if(ID == ID2 && Disc2 == dsc)
{
*(u32*)0xCD0000C0 &= ~0x20;
{
done = true;
break;
}
else if(ID == ID2 && Disc2 != dsc)
{
message( 7, dsc+1, NULL, message_data);
message( 7, Disc2+1, NULL, u_data);
usleep( 5000000 );
break;
}
else if(ID != ID2)
{
message( 8, 0, NULL, message_data);
message( 8, 0, NULL, u_data);
usleep( 5000000 );
break;
}
}
else if(Disc_IsWii() == 0)
{
message( 5, 0, NULL, message_data);
message( 5, 0, NULL, u_data);
usleep( 5000000 );
break;
}
else
{
message( 6, 0, NULL, message_data);
message( 6, 0, NULL, u_data);
usleep( 5000000 );
break;
@ -206,7 +230,7 @@ bool GCDump::__WaitForDisc(u8 dsc, char *minfo, u32 msg, message_callback_t mess
return done;
}
s32 GCDump::DumpGame(progress_callback_t spinner, message_callback_t message, void *spinner_data)
s32 GCDump::DumpGame()
{
static gc_discHdr gcheader ATTRIBUTE_ALIGN(32);
@ -220,8 +244,7 @@ s32 GCDump::DumpGame(progress_callback_t spinner, message_callback_t message, vo
char folder[MAX_FAT_PATH];
bzero(folder, MAX_FAT_PATH);
char gamepath[MAX_FAT_PATH];
bzero(gamepath, MAX_FAT_PATH);
char minfo[74];
bzero(gamepath, MAX_FAT_PATH);
for( j=0; j<2; ++j)
{
@ -253,6 +276,7 @@ s32 GCDump::DumpGame(progress_callback_t spinner, message_callback_t message, vo
}
ID = *(vu32*)(ReadBuffer);
Disc = *(vu8*)(ReadBuffer+0x06);
ApploaderSize = *(vu32*)(ReadBuffer+0x400);
DOLOffset = *(vu32*)(ReadBuffer+0x420);
FSTOffset = *(vu32*)(ReadBuffer+0x424);
@ -285,9 +309,9 @@ s32 GCDump::DumpGame(progress_callback_t spinner, message_callback_t message, vo
snprintf(minfo, sizeof(minfo), "[%.06s] %s", (char *)gcheader.id, gcheader.title);
if(FSTTotal > FSTSize)
message(4, j+1, minfo, spinner_data);
message(4, j+1, minfo, u_data);
else
message(3, 0, minfo, spinner_data);
message(3, 0, minfo, u_data);
gprintf("Dumping: %s %s\n", gcheader.title, compressed ? "compressed" : "full");
@ -312,15 +336,15 @@ s32 GCDump::DumpGame(progress_callback_t spinner, message_callback_t message, vo
gprintf("Writing %s/boot.bin\n", folder);
snprintf(gamepath, sizeof(gamepath), "%s/boot.bin", folder);
gc_done += __DiscWrite(gamepath, 0, 0x440, ReadBuffer, spinner, spinner_data);
gc_done += __DiscWrite(gamepath, 0, 0x440, ReadBuffer);
gprintf("Writing %s/bi2.bin\n", folder);
snprintf(gamepath, sizeof(gamepath), "%s/bi2.bin", folder);
gc_done += __DiscWrite(gamepath, 0x440, 0x2000, ReadBuffer, spinner, spinner_data);
gc_done += __DiscWrite(gamepath, 0x440, 0x2000, ReadBuffer);
gprintf("Writing %s/apploader.img\n", folder);
snprintf(gamepath, sizeof(gamepath), "%s/apploader.img", folder);
gc_done += __DiscWrite(gamepath, 0x2440, ApploaderSize, ReadBuffer, spinner, spinner_data);
gc_done += __DiscWrite(gamepath, 0x2440, ApploaderSize, ReadBuffer);
}
snprintf(gamepath, sizeof(gamepath), "%s/%s [%.06s]%s/game.iso", sfmt((strncmp(gamepartition, "sd", 2) != 0) ? usb_dml_game_dir : DML_DIR, gamepartition).c_str(), gcheader.title, (char *)gcheader.id, j ? "2" : "");
@ -335,7 +359,7 @@ s32 GCDump::DumpGame(progress_callback_t spinner, message_callback_t message, vo
FILE *f;
f = fopen(gamepath, "wb");
ret = __DiscWriteFile(f, 0, (FSTOffset + FSTSize), ReadBuffer, spinner, spinner_data);
ret = __DiscWriteFile(f, 0, (FSTOffset + FSTSize), ReadBuffer);
wrote += (FSTOffset + FSTSize);
gc_done += wrote;
@ -369,7 +393,7 @@ s32 GCDump::DumpGame(progress_callback_t spinner, message_callback_t message, vo
break;
}
}
ret = __DiscWriteFile(f, fst[i].FileOffset, fst[i].FileLength, ReadBuffer, spinner, spinner_data);
ret = __DiscWriteFile(f, fst[i].FileOffset, fst[i].FileLength, ReadBuffer);
gprintf("Writing: %d/%d: %s from 0x%08x to 0x%08x(%i)\n", i, FSTEnt, FSTNameOff + fst[i].NameOffset, fst[i].FileOffset, wrote, align);
if( ret >= 0 )
{
@ -395,7 +419,7 @@ s32 GCDump::DumpGame(progress_callback_t spinner, message_callback_t message, vo
}
else
{
ret = __DiscWrite(gamepath, 0, DiscSize, ReadBuffer, spinner, spinner_data);
ret = __DiscWrite(gamepath, 0, DiscSize, ReadBuffer);
if( ret < 0 )
{
MEM2_free(ReadBuffer);
@ -408,7 +432,7 @@ s32 GCDump::DumpGame(progress_callback_t spinner, message_callback_t message, vo
MEM2_free(FSTBuffer);
if(FSTTotal > FSTSize && !j)
__WaitForDisc(1, minfo, 9, message, spinner_data);
__WaitForDisc(1, 9);
else
break;
}
@ -418,7 +442,7 @@ s32 GCDump::DumpGame(progress_callback_t spinner, message_callback_t message, vo
return gc_skipped;
}
s32 GCDump::CheckSpace(u32 *needed, bool comp, message_callback_t message, void *message_data)
s32 GCDump::CheckSpace(u32 *needed, bool comp)
{
static gc_discHdr gcheader ATTRIBUTE_ALIGN(32);
@ -426,8 +450,6 @@ s32 GCDump::CheckSpace(u32 *needed, bool comp, message_callback_t message, void
u32 size = 0;
u32 j;
char minfo[74];
for( j=0; j<2; ++j)
{
s32 ret = __DiscReadRaw(ReadBuffer, 0, 0x440);
@ -454,7 +476,7 @@ s32 GCDump::CheckSpace(u32 *needed, bool comp, message_callback_t message, void
snprintf(minfo, sizeof(minfo), "[%.06s] %s", (char *)gcheader.id, gcheader.title);
message( 2, 0, minfo, message_data);
message( 2, 0, minfo, u_data);
if(writeexfiles)
{
@ -499,7 +521,7 @@ s32 GCDump::CheckSpace(u32 *needed, bool comp, message_callback_t message, void
{
if((fst[i].FileOffset & (align-1)) == 0 || force_32k_align)
{
correction = 0x00;
correction = 0;
while(((size+correction) & (align-1)) != 0)
correction++;
size += correction;
@ -515,14 +537,14 @@ s32 GCDump::CheckSpace(u32 *needed, bool comp, message_callback_t message, void
if(FSTTotal > FSTSize)
{
if(Disc == 0 && j == 0)
__WaitForDisc(1, minfo, 1, message, message_data);
__WaitForDisc(1, 1);
else if(Disc == 0x01 && j == 0)
__WaitForDisc(0, minfo, 1, message, message_data);
__WaitForDisc(0, 1);
if(j == 1)
{
if(Disc == 0x01)
__WaitForDisc(0, minfo, 1, message, message_data);
__WaitForDisc(0, 1);
break;
}
@ -531,9 +553,31 @@ s32 GCDump::CheckSpace(u32 *needed, bool comp, message_callback_t message, void
break;
}
MEM2_free(ReadBuffer);
DiscSizeCalculated = (size/1024);
*needed = size/0x8000;
gprintf("Free space needed: %d Mb (%x blocks)\n", (size/1024)/1024, size/0x8000);
DiscSizeCalculated = size/0x400;
*needed = (size/0x8000) >> 2;
gprintf("Free space needed: %d Mb (%d blocks)\n", size/0x100000, (size/0x8000) >> 2);
return 0;
}
u32 GCDump::GetFreeSpace(char *path, u32 Value)
{
struct statvfs stats;
memset(&stats, 0, sizeof(stats));
statvfs(path , &stats);
u64 free = (u64)stats.f_frsize * (u64)stats.f_bfree;
switch(Value)
{
case KB:
return free/0x400;
case BL:
return (free/0x8000) >> 2;
case MB:
return free/0x100000;
case GB:
return free/0x40000000;
}
return 0;
}

View File

@ -31,10 +31,18 @@
typedef void (*progress_callback_t)(int status,int total,void *user_data);
typedef void (*message_callback_t)(int message, int info, char *cinfo, void *user_data);
enum spcall
{
KB = 0,
BL,
MB,
GB,
};
class GCDump
{
public:
void Init(bool skip, bool comp, bool wexf, bool align, u32 nretry, u32 rsize, const char* partition, const char* m_DMLgameDir)
void Init(bool skip, bool comp, bool wexf, bool align, u32 nretry, u32 rsize, const char* partition, const char* m_DMLgameDir, progress_callback_t i_spinner, message_callback_t i_message, void *i_udata)
{
skiponerror = skip;
compressed = comp;
@ -45,16 +53,26 @@ public:
gamepartition = partition;
usb_dml_game_dir = m_DMLgameDir;
gc_skipped = 0;
spinner = i_spinner;
message = i_message;
u_data = i_udata;
waitonerror = true;
}
s32 DumpGame(progress_callback_t spinner, message_callback_t message, void *spinner_data);
s32 CheckSpace(u32 *needed, bool comp, message_callback_t message, void *message_data);
s32 DumpGame( );
s32 CheckSpace(u32 *needed, bool comp);
u32 GetFreeSpace(char *path, u32 Value);
private:
progress_callback_t spinner;
message_callback_t message;
void *u_data;
bool force_32k_align;
bool skiponerror;
bool compressed;
bool writeexfiles;
const char* gamepartition;
const char* usb_dml_game_dir;
bool waitonerror;
const char *gamepartition;
const char *usb_dml_game_dir;
char minfo[74];
u8 Disc;
u8 Disc2;
u32 gc_nbrretry;
@ -103,8 +121,8 @@ private:
};
} FST;
s32 __DiscReadRaw(void *outbuf, u32 offset, u32 length);
s32 __DiscWrite(char * path, u32 offset, u32 length, u8 *ReadBuffer, progress_callback_t spinner, void *spinner_data);
s32 __DiscWriteFile(FILE *f, u32 offset, u32 length, u8 *ReadBuffer, progress_callback_t spinner, void *spinner_data);
bool __WaitForDisc(u8 dsc, char *minfo, u32 msg, message_callback_t message, void *message_data);
s32 __DiscWrite(char * path, u32 offset, u32 length, u8 *ReadBuffer);
s32 __DiscWriteFile(FILE *f, u32 offset, u32 length, u8 *ReadBuffer);
bool __WaitForDisc(u8 dsc, u32 msg);
};
#endif

View File

@ -94,6 +94,10 @@ void CMenu::_Messenger(int message, int info, char *cinfo, void *user_data)
m._setThrdMsg(m._t("wbfsop21", L"This is a disc of another game!!"), m.m_progress);
if(message == 9)
m._setThrdMsg(wfmt(m._fmt("wbfsop22", L"Installing %s...\n Please insert disc 2 to continue"), cinfo), m.m_progress);
if(message == 10)
m._setThrdMsg(m._t("wbfsop25", L"Disc read error!! Please clean the disc"), m.m_progress);
if(message == 11)
m._setThrdMsg(m._t("wbfsop26", L"Disc ejected!! Please insert disc again"), m.m_progress);
LWP_MutexUnlock(m.m_mutex);
}
@ -113,7 +117,7 @@ int CMenu::_gameInstaller(void *obj)
WBFS_DiskSpace(&used, &free);
WBFS_DVD_Size(&comp_size, &real_size);
if ((f32)comp_size + (f32)128*1024 >= free * GB_SIZE)
if((f32)comp_size + (f32)128*1024 >= free * GB_SIZE)
{
LWP_MutexLock(m.m_mutex);
m._setThrdMsg(wfmt(m._fmt("wbfsop10", L"Not enough space: %lld blocks needed, %i available"), comp_size, free), 0.f);
@ -154,7 +158,7 @@ int CMenu::_GCgameInstaller(void *obj)
if(skip)
rsize = 8192; // Use small chunks when skip on error is enabled
m_gcdump.Init(skip, comp, wexf, alig, nretry, rsize,DeviceName[currentPartition],m.m_DMLgameDir.c_str());
m_gcdump.Init(skip, comp, wexf, alig, nretry, rsize,DeviceName[currentPartition],m.m_DMLgameDir.c_str(), CMenu::_addDiscProgress, CMenu::_Messenger, obj);
int ret;
m.m_progress = 0.f;
@ -170,7 +174,7 @@ int CMenu::_GCgameInstaller(void *obj)
u32 needed = 0;
ret = m_gcdump.CheckSpace(&needed, comp, CMenu::_Messenger, obj);
ret = m_gcdump.CheckSpace(&needed, comp);
if(ret != 0)
{
m._setThrdMsg(m._t("wbfsop9", L"An error has occurred"), 1.f);
@ -178,20 +182,22 @@ int CMenu::_GCgameInstaller(void *obj)
return ret;
}
if (fsop_GetFreeSpaceKb(partition) <= needed)
if(m_gcdump.GetFreeSpace(partition, BL) <= needed)
{
gprintf("Free space available: %d Mb (%d blocks)\n", m_gcdump.GetFreeSpace(partition, MB), m_gcdump.GetFreeSpace(partition, BL));
LWP_MutexLock(m.m_mutex);
m._setThrdMsg(wfmt(m._fmt("wbfsop10", L"Not enough space: %d blocks needed, %d available"), needed, fsop_GetFreeSpaceKb(partition)), 0.f);
m._setThrdMsg(wfmt(m._fmt("wbfsop24", L"Not enough space: %d blocks needed, %d available"), needed, m_gcdump.GetFreeSpace(partition, BL)), 0.f);
LWP_MutexUnlock(m.m_mutex);
ret = -1;
}
else
{
gprintf("Free space available: %d Mb (%d blocks)\n", m_gcdump.GetFreeSpace(partition, MB), m_gcdump.GetFreeSpace(partition, BL));
LWP_MutexLock(m.m_mutex);
m._setThrdMsg(L"", 0);
LWP_MutexUnlock(m.m_mutex);
ret = m_gcdump.DumpGame(CMenu::_addDiscProgress, CMenu::_Messenger, obj);
ret = m_gcdump.DumpGame();
LWP_MutexLock(m.m_mutex);
if(ret == 0)
m._setThrdMsg(m._t("wbfsop8", L"Game installed"), 1.f);

View File

@ -210,7 +210,7 @@ wbfsadddlg=Plaats het te kopiëren spel in de disc sleuf, klik daarna op Start.
wbfsop1=Installeer Spel
wbfsop10=Niet genoeg ruimte: %i blokken benodigd, %i beschikbaar
wbfsop11=Kopieër Spel
wbfsop12=DVD Lees Fout(%d)
wbfsop12=DVD lees fout(%d)
wbfsop13=Spel geïnstalleerd, maar bevat %d leesfouten
wbfsop14=Spel gekopieërd, klik op terug om spel te starten
wbfsop15=Benodigde ruimte aan het berekenen voor %s
@ -223,6 +223,9 @@ wbfsop20=Je hebt disc %d terug in de disc sleuf gedaan!
wbfsop21=Dit is een disc van een ander spel!
wbfsop22=Bezig met installeren van %s...\nDoe disc 2 in de disc sleuf om door the gaan
wbfsop23=Benodigde ruimte aan het berekenen voor %s...\nDoe disc %d in de disc sleuf om door the gaan
wbfsop24=Niet genoeg ruimte:: %d blokken benodigd, %d beschikbaar
wbfsop25=DVD lees fout!! Maak de disc schoon A.U.B.
wbfsop26=Disc verwijderd!! Doe de disc terug in de disc sleuf A.U.B.
wbfsop4=Terug
wbfsop5=Start
wbfsop6=Bezig met installeren van [%s] %s...

View File

@ -218,8 +218,19 @@ wbfsop11=Copy Game
wbfsop12=DVDError(%d)
wbfsop13=Game installed, but disc contains errors (%d)
wbfsop14=Game copied, press Back to boot the game.
wbfsop15=Copying [%s] %s...
wbfsop15=Calculating space needed for %s
wbfsop16=Installing %s
wbfsop17=Installing %s disc %d/2
wbfsop18=This is a Wii disc!
wbfsop19=This is not a Gamecube disc!
wbfsop2=Delete Game
wbfsop20=You inserted disc %d again!!
wbfsop21=This is a disc of another game!!
wbfsop22=Installing %s...\n Please insert disc 2 to continue
wbfsop23=Calculating space needed for %s...\n Please insert disc %d to continue
wbfsop24=Not enough space: %d blocks needed, %d available
wbfsop25=Disc read error!! Please clean the disc
wbfsop26=Disc ejected!! Please insert disc again
wbfsop4=Back
wbfsop5=Go
wbfsop6=Installing [%s] %s...