From d611849d6f0ab4fa324d9ea5de61fba3ed7c7de4 Mon Sep 17 00:00:00 2001 From: "overjoy.psm" Date: Fri, 17 Feb 2012 02:35:42 +0000 Subject: [PATCH] * 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 --- source/gui/text.cpp | 24 +++++ source/gui/text.hpp | 1 + source/loader/disc.h | 8 +- source/loader/gc_disc.cpp | 78 +++++++++++++++ source/loader/gc_disc.hpp | 9 ++ source/loader/utils.h | 3 + source/menu/menu.hpp | 1 + source/menu/menu_wbfs.cpp | 107 +++++++++++++++++---- source/music/AifDecoder.cpp | 186 ++++++++++++++++++------------------ 9 files changed, 304 insertions(+), 113 deletions(-) create mode 100644 source/loader/gc_disc.cpp create mode 100644 source/loader/gc_disc.hpp diff --git a/source/gui/text.cpp b/source/gui/text.cpp index 8d837e4b..9158a5d2 100644 --- a/source/gui/text.cpp +++ b/source/gui/text.cpp @@ -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; + } + } + } +} diff --git a/source/gui/text.hpp b/source/gui/text.hpp index a3a2b5d4..262ccf7c 100644 --- a/source/gui/text.hpp +++ b/source/gui/text.hpp @@ -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) diff --git a/source/loader/disc.h b/source/loader/disc.h index ff2dc613..1ec5c9fc 100644 --- a/source/loader/disc.h +++ b/source/loader/disc.h @@ -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 diff --git a/source/loader/gc_disc.cpp b/source/loader/gc_disc.cpp new file mode 100644 index 00000000..a3b90e35 --- /dev/null +++ b/source/loader/gc_disc.cpp @@ -0,0 +1,78 @@ +#include +#include +#include +#include +#include +#include + +#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; +} \ No newline at end of file diff --git a/source/loader/gc_disc.hpp b/source/loader/gc_disc.hpp new file mode 100644 index 00000000..bf3771a9 --- /dev/null +++ b/source/loader/gc_disc.hpp @@ -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 \ No newline at end of file diff --git a/source/loader/utils.h b/source/loader/utils.h index 061aa19f..3267a939 100644 --- a/source/loader/utils.h +++ b/source/loader/utils.h @@ -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))) diff --git a/source/menu/menu.hpp b/source/menu/menu.hpp index fe0fb7fa..49136666 100644 --- a/source/menu/menu.hpp +++ b/source/menu/menu.hpp @@ -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); // diff --git a/source/menu/menu_wbfs.cpp b/source/menu/menu_wbfs.cpp index 04f23c41..e3b516e6 100644 --- a/source/menu/menu_wbfs.cpp +++ b/source/menu/menu_wbfs.cpp @@ -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(); diff --git a/source/music/AifDecoder.cpp b/source/music/AifDecoder.cpp index 012ffd74..19c10aa1 100644 --- a/source/music/AifDecoder.cpp +++ b/source/music/AifDecoder.cpp @@ -26,7 +26,6 @@ #include #include #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; }