* Added DML Ex GC disc dumper. This makes it possible to install GC discs and dump them straight into DML Ex format

* Fixed gc_discHdr struct
* Updated aiff decoder to dimok's code (Thnx)

Todo for GC disc dumper:
* Add retry on read error
* Add skip on read error pos
* Add some more checks
This commit is contained in:
overjoy.psm 2012-02-17 02:35:42 +00:00
parent 6c6a57cab2
commit d611849d6f
9 changed files with 304 additions and 113 deletions

View File

@ -480,3 +480,27 @@ void Asciify( wchar_t *str )
} }
*ctr = '\0'; *ctr = '\0';
} }
void Asciify2( char *str )
{
int i=0;
for( i=0; i < strlen(str); ++i )
{
if( str[i] < 0x20 || str[i] > 0x7F )
str[i] = '_';
else {
switch( str[i] )
{
case '*':
case '\"':
case ':':
case '|':
case '<':
case '>':
case '?':
str[i] = '_';
break;
}
}
}
}

View File

@ -67,5 +67,6 @@ std::string lowerCase(std::string text);
std::string ltrim(std::string s); std::string ltrim(std::string s);
std::string rtrim(std::string s); std::string rtrim(std::string s);
void Asciify( wchar_t *str ); void Asciify( wchar_t *str );
void Asciify2( char *str );
#endif // !defined(__TEXT_HPP) #endif // !defined(__TEXT_HPP)

View File

@ -81,11 +81,11 @@ struct gc_discHdr
/* Magic word */ /* Magic word */
u32 magic; u32 magic;
/* Padding */
u8 unused2[4];
/* Game title */ /* Game title */
char title[124]; char title[64];
/* Padding */
u8 unused2[64];
} ATTRIBUTE_PACKED; } ATTRIBUTE_PACKED;
#ifdef __cplusplus #ifdef __cplusplus

78
source/loader/gc_disc.cpp Normal file
View File

@ -0,0 +1,78 @@
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <ogcsys.h>
#include <dirent.h>
#include <sys/statvfs.h>
#include "gc_disc.hpp"
#include "DeviceHandler.hpp"
#include "disc.h"
#include "utils.h"
#include "wdvd.h"
#include "text.hpp"
s32 __DiscReadRaw(void *outbuf, u32 offset, u32 length)
{
return WDVD_UnencryptedRead(outbuf, length, offset);
}
s32 GC_GameDumper(progress_callback_t spinner, void *spinner_data)
{
static gc_discHdr gcheader ATTRIBUTE_ALIGN(32);
FILE *f;
u8 *ReadBuffer = (u8 *)memalign(32, READSIZE);
u32 DiscSec = 0;
u32 ApploaderSize = 0;
char folder[MAX_FAT_PATH];
bzero(folder, MAX_FAT_PATH);
char gamepath[MAX_FAT_PATH];
bzero(gamepath, MAX_FAT_PATH);
Disc_ReadGCHeader(&gcheader);
Asciify2(gcheader.title);
snprintf(folder, sizeof(folder), "%s:/games/%s [%s]", DeviceName[SD], gcheader.title, (char *)gcheader.id);
makedir((char *)folder);
snprintf(gamepath, sizeof(gamepath), "%s/game.iso", folder);
f = fopen(gamepath, "wb");
while( DiscSec < 0xAE0B )
{
__DiscReadRaw(ReadBuffer, DiscSec*READSIZE, READSIZE);
fwrite(ReadBuffer, 1, READSIZE, f);
spinner(DiscSec, 0xAE0B, spinner_data);
DiscSec++;
}
fclose(f);
snprintf(folder, sizeof(folder), "%s:/games/%s [%s]/sys", DeviceName[SD], gcheader.title, (char *)gcheader.id);
makedir((char *)folder);
snprintf(gamepath, sizeof(gamepath), "%s/boot.bin", folder);
__DiscReadRaw(ReadBuffer, 0, 0x440);
f = fopen(gamepath, "wb");
fwrite(ReadBuffer, 1, 0x440, f);
fclose(f);
ApploaderSize = *(vu32*)(ReadBuffer+0x400);
snprintf(gamepath, sizeof(gamepath), "%s/bi2.bin", folder);
__DiscReadRaw(ReadBuffer, 0x440, 0x2000);
f = fopen(gamepath, "wb");
fwrite(ReadBuffer, 1, 0x2000, f);
fclose(f);
snprintf(gamepath, sizeof(gamepath), "%s/apploader.img", folder);
__DiscReadRaw(ReadBuffer, 0x2440, ApploaderSize);
f = fopen(gamepath, "wb");
fwrite(ReadBuffer, 1, ApploaderSize, f);
fclose(f);
free(ReadBuffer);
return 0;
}

View File

@ -0,0 +1,9 @@
#ifndef GC_DISC_H_
#define GC_DISC_H_
typedef void (*progress_callback_t)(int status,int total,void *user_data);
s32 GC_GameDumper(progress_callback_t spinner, void *spinner_data);
s32 GC_DiskSpace(u64 *free);
#endif

View File

@ -7,6 +7,9 @@
#define MB_SIZE 1048576.0 #define MB_SIZE 1048576.0
#define GB_SIZE 1073741824.0 #define GB_SIZE 1073741824.0
#define READSIZE (32*1024)
#define MAX_FAT_PATH 1024
/* Macros */ /* Macros */
#define round_up(x,n) (-(-(x) & -(n))) #define round_up(x,n) (-(-(x) & -(n)))

View File

@ -929,6 +929,7 @@ private:
void _getGrabStatus(void); void _getGrabStatus(void);
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);
wstringEx _optBoolToString(int b); wstringEx _optBoolToString(int b);
void _stopSounds(void); void _stopSounds(void);
// //

View File

@ -2,6 +2,7 @@
#include "menu.hpp" #include "menu.hpp"
#include "loader/wbfs.h" #include "loader/wbfs.h"
#include "lockMutex.hpp" #include "lockMutex.hpp"
#include "loader/gc_disc.hpp"
using namespace std; using namespace std;
@ -105,11 +106,63 @@ int CMenu::_gameInstaller(void *obj)
return ret; return ret;
} }
int CMenu::_GCgameInstaller(void *obj)
{
CMenu &m = *(CMenu *)obj;
int ret;
if (!DeviceHandler::Instance()->IsInserted(SD))
{
m.m_thrdWorking = false;
return -1;
}
struct statvfs stats;
memset(&stats, 0, sizeof(stats));
statvfs("sd:/" , &stats);
u64 free = (u64)stats.f_frsize * (u64)stats.f_bfree;
int blockfree = free/0x8000;
if (blockfree <= 44556)
{
LWP_MutexLock(m.m_mutex);
m._setThrdMsg(wfmt(m._fmt("wbfsop11", L"Not enough space : 44557 blocks needed, %d available"), blockfree), 0.f);
LWP_MutexUnlock(m.m_mutex);
ret = -1;
}
else
{
LWP_MutexLock(m.m_mutex);
m._setThrdMsg(L"", 0);
LWP_MutexUnlock(m.m_mutex);
ret=0;
ret = GC_GameDumper(CMenu::_addDiscProgress, obj);
LWP_MutexLock(m.m_mutex);
if (ret == 0)
m._setThrdMsg(m._t("wbfsop8", L"Game installed"), 1.f);
else
m._setThrdMsg(m._t("wbfsop9", L"An error has occurred"), 1.f);
LWP_MutexUnlock(m.m_mutex);
slotLight(true);
}
m.m_thrdWorking = false;
return ret;
}
bool CMenu::_wbfsOp(CMenu::WBFS_OP op) bool CMenu::_wbfsOp(CMenu::WBFS_OP op)
{ {
lwp_t thread = 0; lwp_t thread = 0;
static discHdr header ATTRIBUTE_ALIGN(32); static discHdr header ATTRIBUTE_ALIGN(32);
static gc_discHdr gcheader ATTRIBUTE_ALIGN(32);
bool done = false; bool done = false;
bool upd_usb = false;
bool upd_dml = false;
bool out = false; bool out = false;
bool del_cover = true; bool del_cover = true;
struct AutoLight { AutoLight(void) { } ~AutoLight(void) { slotLight(false); } } aw; struct AutoLight { AutoLight(void) { } ~AutoLight(void) { slotLight(false); } } aw;
@ -168,27 +221,43 @@ bool CMenu::_wbfsOp(CMenu::WBFS_OP op)
out = true; out = true;
break; break;
} }
if (Disc_IsWii() < 0) if (Disc_IsWii() == 0)
{ {
error(_t("wbfsoperr3", L"This is not a Wii disc!")); Disc_ReadHeader(&header);
out = true;
break;
}
Disc_ReadHeader(&header);
if (_searchGamesByID((const char *) header.id).size() != 0) if (_searchGamesByID((const char *) header.id).size() != 0)
{
error(_t("wbfsoperr4", L"Game already installed"));
out = true;
break;
}
cfPos = string((char *) header.id);
m_btnMgr.setText(m_wbfsLblDialog, wfmt(_fmt("wbfsop6", L"Installing [%s] %s..."), string((const char *)header.id, sizeof header.id).c_str(), string((const char *)header.title, sizeof header.title).c_str()));
done = true;
upd_usb = true;
m_thrdWorking = true;
m_thrdProgress = 0.f;
m_thrdMessageAdded = false;
LWP_CreateThread(&thread, (void *(*)(void *))CMenu::_gameInstaller, (void *)this, 0, 8 * 1024, 64);
}
else if(Disc_IsGC() == 0)
{ {
error(_t("wbfsoperr4", L"Game already installed")); Disc_ReadGCHeader(&gcheader);
cfPos = string((char *) gcheader.id);
m_btnMgr.setText(m_wbfsLblDialog, wfmt(_fmt("wbfsop6", L"Installing [%s] %s..."), string((const char *)gcheader.id, sizeof gcheader.id).c_str(), string((const char *)gcheader.title, sizeof gcheader.title).c_str()));
done = true;
upd_dml = true;
m_thrdWorking = true;
m_thrdProgress = 0.f;
m_thrdMessageAdded = false;
LWP_CreateThread(&thread, (void *(*)(void *))CMenu::_GCgameInstaller, (void *)this, 0, 8 * 1024, 64);
}
else
{
error(_t("wbfsoperr3", L"This is not a Wii or GC disc!"));
out = true; out = true;
break; break;
} }
cfPos = string((char *) header.id);
m_btnMgr.setText(m_wbfsLblDialog, wfmt(_fmt("wbfsop6", L"Installing [%s] %s..."), string((const char *)header.id, sizeof header.id).c_str(), string((const char *)header.title, sizeof header.title).c_str()));
done = true;
m_thrdWorking = true;
m_thrdProgress = 0.f;
m_thrdMessageAdded = false;
LWP_CreateThread(&thread, (void *(*)(void *))CMenu::_gameInstaller, (void *)this, 0, 8 * 1024, 64);
break; break;
case CMenu::WO_REMOVE_GAME: case CMenu::WO_REMOVE_GAME:
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);
@ -228,7 +297,11 @@ bool CMenu::_wbfsOp(CMenu::WBFS_OP op)
if (done && (op == CMenu::WO_REMOVE_GAME || op == CMenu::WO_ADD_GAME)) if (done && (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());
UpdateCache(COVERFLOW_USB); if( upd_dml )
UpdateCache(COVERFLOW_DML);
if( upd_usb )
UpdateCache(COVERFLOW_USB);
_loadList(); _loadList();
_initCF(); _initCF();

View File

@ -26,7 +26,6 @@
#include <string.h> #include <string.h>
#include <math.h> #include <math.h>
#include "AifDecoder.hpp" #include "AifDecoder.hpp"
#include "gecko.h"
typedef struct typedef struct
{ {
@ -52,64 +51,64 @@ typedef struct
# define HUGE_VAL HUGE # define HUGE_VAL HUGE
#endif #endif
# define UnsignedToFloat(u) (((double)((long)(u - 2147483647L - 1))) + 2147483648.0) # define UnsignedToFloat(u) (((double)((long)(u - 2147483647L - 1))) + 2147483648.0)
static double ConvertFromIeeeExtended(const unsigned char* bytes) static double ConvertFromIeeeExtended(const unsigned char* bytes)
{ {
double f; double f;
int expon; int expon;
unsigned long hiMant, loMant; unsigned long hiMant, loMant;
expon = ((bytes[0] & 0x7F) << 8) | (bytes[1] & 0xFF); expon = ((bytes[0] & 0x7F) << 8) | (bytes[1] & 0xFF);
hiMant = ((unsigned long)(bytes[2] & 0xFF) << 24) hiMant = ((unsigned long)(bytes[2] & 0xFF) << 24)
| ((unsigned long)(bytes[3] & 0xFF) << 16) | ((unsigned long)(bytes[3] & 0xFF) << 16)
| ((unsigned long)(bytes[4] & 0xFF) << 8) | ((unsigned long)(bytes[4] & 0xFF) << 8)
| ((unsigned long)(bytes[5] & 0xFF)); | ((unsigned long)(bytes[5] & 0xFF));
loMant = ((unsigned long)(bytes[6] & 0xFF) << 24) loMant = ((unsigned long)(bytes[6] & 0xFF) << 24)
| ((unsigned long)(bytes[7] & 0xFF) << 16) | ((unsigned long)(bytes[7] & 0xFF) << 16)
| ((unsigned long)(bytes[8] & 0xFF) << 8) | ((unsigned long)(bytes[8] & 0xFF) << 8)
| ((unsigned long)(bytes[9] & 0xFF)); | ((unsigned long)(bytes[9] & 0xFF));
if (expon == 0 && hiMant == 0 && loMant == 0) { if (expon == 0 && hiMant == 0 && loMant == 0) {
f = 0; f = 0;
} }
else { else {
if (expon == 0x7FFF) { if (expon == 0x7FFF) {
f = HUGE_VAL; f = HUGE_VAL;
} }
else { else {
expon -= 16383; expon -= 16383;
f = ldexp(UnsignedToFloat(hiMant), expon-=31); f = ldexp(UnsignedToFloat(hiMant), expon-=31);
f += ldexp(UnsignedToFloat(loMant), expon-=32); f += ldexp(UnsignedToFloat(loMant), expon-=32);
} }
} }
if (bytes[0] & 0x80) if (bytes[0] & 0x80)
return -f; return -f;
else else
return f; return f;
} }
AifDecoder::AifDecoder(const char * filepath) AifDecoder::AifDecoder(const char * filepath)
: SoundDecoder(filepath) : SoundDecoder(filepath)
{ {
SoundType = SOUND_AIF; SoundType = SOUND_AIF;
if(!file_fd) if(!file_fd)
return; return;
OpenFile(); OpenFile();
} }
AifDecoder::AifDecoder(const u8 * snd, int len) AifDecoder::AifDecoder(const u8 * snd, int len)
: SoundDecoder(snd, len) : SoundDecoder(snd, len)
{ {
SoundType = SOUND_AIF; SoundType = SOUND_AIF;
if(!file_fd) if(!file_fd)
return; return;
OpenFile(); OpenFile();
} }
AifDecoder::~AifDecoder() AifDecoder::~AifDecoder()
@ -118,8 +117,8 @@ AifDecoder::~AifDecoder()
void AifDecoder::OpenFile() void AifDecoder::OpenFile()
{ {
SWaveHdr Header; SWaveHdr Header;
file_fd->read((u8 *) &Header, sizeof(SWaveHdr)); file_fd->read((u8 *) &Header, sizeof(SWaveHdr));
if (Header.magicRIFF != 'FORM') if (Header.magicRIFF != 'FORM')
{ {
@ -131,34 +130,29 @@ void AifDecoder::OpenFile()
CloseFile(); CloseFile();
return; return;
} }
SWaveChunk WaveChunk;
u32 limit = 0;
while(limit != 60) u32 magic = 0;
while(1)
{ {
int ret = file_fd->read((u8 *) &WaveChunk, sizeof(SWaveChunk)); int ret = file_fd->read((u8 *) &magic, sizeof(magic));
if(ret <= 0) if(ret <= 0)
{ {
CloseFile(); CloseFile();
return; return;
} }
if(WaveChunk.magicDATA == 'COMM') if(magic == 'COMM')
break; break;
else
file_fd->seek(-sizeof(SWaveChunk)+1, SEEK_CUR); file_fd->seek(-3, SEEK_CUR);
limit++;
} }
DataOffset = file_fd->tell()+WaveChunk.size;
SAIFFCommChunk CommHdr; // seek back to COMM chunk start
file_fd->seek(file_fd->tell()-sizeof(SWaveChunk), SEEK_SET); file_fd->seek(-sizeof(magic), SEEK_CUR);
file_fd->read((u8 *) &CommHdr, sizeof(SAIFFCommChunk));
SAIFFCommChunk CommHdr;
file_fd->read((u8 *) &CommHdr, sizeof(SAIFFCommChunk));
if(CommHdr.fccCOMM != 'COMM') if(CommHdr.fccCOMM != 'COMM')
{ {
@ -166,29 +160,37 @@ void AifDecoder::OpenFile()
return; return;
} }
file_fd->seek(DataOffset, SEEK_SET); // Seek to next chunk start
file_fd->seek(-sizeof(SAIFFCommChunk) + sizeof(SWaveChunk) + CommHdr.size, SEEK_CUR);
SAIFFSSndChunk SSndChunk; int ret = -1;
SWaveChunk chunkHdr;
limit = 0; memset(&chunkHdr, 0, sizeof(SWaveChunk));
while(limit != 60) do
{ {
file_fd->read((u8 *) &SSndChunk, sizeof(SAIFFSSndChunk)); // Seek to next chunk start
file_fd->seek(chunkHdr.size, SEEK_CUR);
if(SSndChunk.fccSSND == 'SSND') ret = file_fd->read((u8 *) &chunkHdr, sizeof(SWaveChunk));
break; }
while(ret > 0 && chunkHdr.magicDATA != 'SSND');
file_fd->seek(-sizeof(SAIFFSSndChunk)+1, SEEK_CUR); // Seek back to start of SSND chunk
DataOffset += 1; file_fd->seek(-sizeof(SWaveChunk), SEEK_CUR);
limit++; SAIFFSSndChunk SSndChunk;
file_fd->read((u8 *) &SSndChunk, sizeof(SAIFFSSndChunk));
if(SSndChunk.fccSSND != 'SSND')
{
CloseFile();
return;
} }
DataOffset += sizeof(SAIFFSSndChunk); DataOffset = file_fd->tell();
DataSize = SSndChunk.size-8; DataSize = SSndChunk.size-8;
SampleRate = (u32) ConvertFromIeeeExtended(CommHdr.freq); SampleRate = (u32) ConvertFromIeeeExtended(CommHdr.freq);
Format = VOICE_STEREO_16BIT; Format = VOICE_STEREO_16BIT;
if(CommHdr.channels == 1 && CommHdr.bps == 8) if(CommHdr.channels == 1 && CommHdr.bps == 8)
Format = VOICE_MONO_8BIT; Format = VOICE_MONO_8BIT;
@ -199,35 +201,35 @@ void AifDecoder::OpenFile()
else if (CommHdr.channels == 2 && CommHdr.bps == 16) else if (CommHdr.channels == 2 && CommHdr.bps == 16)
Format = VOICE_STEREO_16BIT; Format = VOICE_STEREO_16BIT;
Decode(); Decode();
} }
void AifDecoder::CloseFile() void AifDecoder::CloseFile()
{ {
if(file_fd) if(file_fd)
delete file_fd; delete file_fd;
file_fd = NULL; file_fd = NULL;
} }
int AifDecoder::Read(u8 * buffer, int buffer_size, int) int AifDecoder::Read(u8 * buffer, int buffer_size, int)
{ {
if(!file_fd) if(!file_fd)
return -1; return -1;
if(CurPos >= (int) DataSize) if(CurPos >= (int) DataSize)
return 0; return 0;
file_fd->seek(DataOffset+CurPos, SEEK_SET); file_fd->seek(DataOffset+CurPos, SEEK_SET);
if(buffer_size > (int) DataSize-CurPos) if(buffer_size > (int) DataSize-CurPos)
buffer_size = DataSize-CurPos; buffer_size = DataSize-CurPos;
int read = file_fd->read(buffer, buffer_size); int read = file_fd->read(buffer, buffer_size);
if(read > 0) if(read > 0)
{ {
CurPos += read; CurPos += read;
} }
return read; return read;
} }