* 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';
}
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 rtrim(std::string s);
void Asciify( wchar_t *str );
void Asciify2( char *str );
#endif // !defined(__TEXT_HPP)

View File

@ -81,11 +81,11 @@ struct gc_discHdr
/* Magic word */
u32 magic;
/* Padding */
u8 unused2[4];
/* Game title */
char title[124];
char title[64];
/* Padding */
u8 unused2[64];
} ATTRIBUTE_PACKED;
#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 GB_SIZE 1073741824.0
#define READSIZE (32*1024)
#define MAX_FAT_PATH 1024
/* Macros */
#define round_up(x,n) (-(-(x) & -(n)))

View File

@ -929,6 +929,7 @@ private:
void _getGrabStatus(void);
static void _addDiscProgress(int status, int total, void *user_data);
static int _gameInstaller(void *obj);
static int _GCgameInstaller(void *obj);
wstringEx _optBoolToString(int b);
void _stopSounds(void);
//

View File

@ -2,6 +2,7 @@
#include "menu.hpp"
#include "loader/wbfs.h"
#include "lockMutex.hpp"
#include "loader/gc_disc.hpp"
using namespace std;
@ -105,11 +106,63 @@ int CMenu::_gameInstaller(void *obj)
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)
{
lwp_t thread = 0;
static discHdr header ATTRIBUTE_ALIGN(32);
static gc_discHdr gcheader ATTRIBUTE_ALIGN(32);
bool done = false;
bool upd_usb = false;
bool upd_dml = false;
bool out = false;
bool del_cover = true;
struct AutoLight { AutoLight(void) { } ~AutoLight(void) { slotLight(false); } } aw;
@ -168,27 +221,43 @@ bool CMenu::_wbfsOp(CMenu::WBFS_OP op)
out = true;
break;
}
if (Disc_IsWii() < 0)
if (Disc_IsWii() == 0)
{
error(_t("wbfsoperr3", L"This is not a Wii disc!"));
out = true;
break;
}
Disc_ReadHeader(&header);
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;
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;
case CMenu::WO_REMOVE_GAME:
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))
{
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();
_initCF();

View File

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