From 1cb8a493d9cd55039c710a029024cf299e42e549 Mon Sep 17 00:00:00 2001 From: "overjoy.psm" Date: Wed, 2 May 2012 23:08:11 +0000 Subject: [PATCH] * Enabled nand extract features for full nand and game saves * Made nand emulation kind of noob prove * Wiiflow will search for a valid FAT32 partition if nand emu is enabled, but no partition is selected * Wiiflow will now offer to extract the nand if nand emu is enabled, and no nand for nand emulation is available * Wiiflow will now offer to extract a game save if nand emulation is enabled, a save is found on real nand and no save is found on emu nand.cpp * Illegal chars for FAT are now escaped the 'd2x' way in the nand file extractor TODO: * Add nand extract functions to game config menu's * Add feature to flash a save back to real nand --- source/channel/nand.cpp | 223 +++++++----- source/channel/nand.hpp | 24 +- source/defines.h | 2 +- source/menu/menu.cpp | 1 + source/menu/menu.hpp | 58 +++- source/menu/menu_config.cpp | 97 +----- source/menu/menu_game.cpp | 55 ++- source/menu/menu_main.cpp | 38 ++- source/menu/menu_nandemu.cpp | 640 +++++++++++++++++++++++++++++++++++ source/music/WavDecoder.cpp | 22 +- 10 files changed, 948 insertions(+), 212 deletions(-) create mode 100644 source/menu/menu_nandemu.cpp diff --git a/source/channel/nand.cpp b/source/channel/nand.cpp index dff9ce0e..580de1f3 100644 --- a/source/channel/nand.cpp +++ b/source/channel/nand.cpp @@ -51,6 +51,8 @@ config_header *cfg_hdr; bool tbdec = false; bool configloaded = false; +static const int d2xfatrepl_len = 7; + static NandDevice NandDeviceList[] = { { "Disable", 0, 0x00, 0x00 }, @@ -412,53 +414,43 @@ bool Nand::__FileExists(const char *path, ...) return false; } -u32 Nand::__TestNandPath(const char *path) +void Nand::__FATify(char *ptr, const char *str) { - if(!strncmp(path, "/import", 7)) return 0; - if(!strncmp(path, "/meta", 5)) return 0; - if(!strncmp(path, "/shared", 7) && !n_dumpwsc && !n_dumpwvc) return 1; - if(!strncmp(path, "/sys", 4)) return 0; - - if(!strncmp(path, "/ticket/00000001/", 17)) + char ctr; + while ((ctr = *(str++)) != '\0') { - const char *tmp = path + 17; - if(!strncmp(tmp, "00000002.tik", 8) && !n_dumpmen) return 1; // Menu - if(strncmp(tmp, "00000002.tik", 8) && !n_dumpios) return 1; // IOSs - return 0; + const char *esc; + switch (ctr) + { + case '"': + esc = "&qt;"; + break; + case '*': + esc = "&st;"; + break; + case ':': + esc = "&cl;"; + break; + case '<': + esc = "<"; + break; + case '>': + esc = ">"; + break; + case '?': + esc = "&qm;"; + break; + case '|': + esc = "&vb;"; + break; + default: + *(ptr++) = ctr; + continue; + } + strcpy(ptr, esc); + ptr += 4; } - if(!strncmp(path, "/ticket/00010001/", 17)) - { - const char *tmp = path + 17; - if(!strncmp(tmp, "48XXXXXX.tik", 2) && n_dumpwsc) return 0; // SC - if(strncmp(tmp, "48XXXXXX.tik", 2) && n_dumpwvc) return 0; // WW&VC - return 1; - } - if(!strncmp(path, "/ticket/00010002/", 17) && !n_dumpwsc) return 1; // SC - if(!strncmp(path, "/ticket/00010005/", 17) && !n_dumpwgs) return 1; // DLC? - if(!strncmp(path, "/ticket/00010008/", 17) && !n_dumpwsc) return 1; // Hidden SC - - if(!strncmp(path, "/title/00000001/", 16)) - { - const char *tmp = path + 16; - if(!strncmp(tmp, "00000002", 8) && n_dumpmen) return 0; // Menu - if(strncmp(tmp, "00000002", 8) && n_dumpios) return 0; // IOSs - return 1; - } - if(!strncmp(path, "/title/00010000/", 16) && !n_dumpwgs) return 1; // Saves - if(!strncmp(path, "/title/00010001/", 16)) - { - const char *tmp = path + 16; - if(!strncmp(tmp, "48XXXXXX", 2) && n_dumpwsc) return 0; // SC - if(strncmp(tmp, "48XXXXXX", 2) && n_dumpwvc) return 0; // WW&VC - return 1; - } - if(!strncmp(path, "/title/00010002/", 16) && !n_dumpwsc) return 1; // SC - if(!strncmp(path, "/title/00010004/", 16) && !n_dumpwgs) return 1; // Saves - if(!strncmp(path, "/title/00010005/", 16) && !n_dumpwgs) return 1; // DLC - if(!strncmp(path, "/title/00010008/", 16) && !n_dumpwsc) return 1; // Hidden SC - - if(!strncmp(path, "/tmp", 4)) return 0; - return 0; + *ptr = '\0'; } s32 Nand::__FlashNandFile(const char *source, const char *dest) @@ -526,9 +518,7 @@ s32 Nand::__FlashNandFile(const char *source, const char *dest) s32 Nand::__DumpNandFile(const char *source, const char *dest) { - if(__TestNandPath(source)) - return 0; - + FileDone = 0; s32 fd = ISFS_Open(source, ISFS_OPEN_READ); if (fd < 0) { @@ -536,8 +526,29 @@ s32 Nand::__DumpNandFile(const char *source, const char *dest) return fd; } + fstats *status = (fstats *)MEM2_alloc(sizeof(fstats)); + s32 ret = ISFS_GetFileStats(fd, status); + if (ret < 0) + { + gprintf("Error: ISFS_GetFileStats(%d) %d\n", fd, ret); + ISFS_Close(fd); + MEM2_free(status); + return ret; + } + + if(fake) + { + NandSize += status->file_length; + if(showprogress) + dumper(NandSize, 0x1f400000, 0x1f400000, NandSize, FilesDone, FoldersDone, (char *)"", data); + + ISFS_Close(fd); + MEM2_free(status); + return 0; + } + if(__FileExists(dest)) - remove(dest); + remove(dest); FILE *file = fopen(dest, "wb"); if (!file) @@ -546,19 +557,8 @@ s32 Nand::__DumpNandFile(const char *source, const char *dest) ISFS_Close(fd); return 0; } - - fstats *status = (fstats *)MEM2_alloc(sizeof(fstats)); - s32 ret = ISFS_GetFileStats(fd, status); - if (ret < 0) - { - gprintf("Error: ISFS_GetFileStats(%d) %d\n", fd, ret); - ISFS_Close(fd); - SAFE_CLOSE(file); - MEM2_free(status); - return ret; - } - gprintf("Dumping: %s (%uKB)...", source, (status->file_length / 0x400)+1); + gprintf("Dumping: %s (%ukb)...", source, (status->file_length / 0x400)+1); u8 *buffer = (u8 *)MEM2_alloc(BLOCK); u32 toread = status->file_length; @@ -590,13 +590,28 @@ s32 Nand::__DumpNandFile(const char *source, const char *dest) return ret; } toread -= size; + NandDone += size; + FileDone += size; + + if(showprogress) + { + const char *file = strrchr(source, '/')+1; + dumper(NandDone, NandSize, status->file_length, FileDone, FilesDone, FoldersDone, (char *)file, data); + } + } + FilesDone++; + if(showprogress) + { + const char *file = strrchr(source, '/')+1; + dumper(NandDone, NandSize, status->file_length, FileDone, FilesDone, FoldersDone, (char *)file, data); } gprintf(" done!\n"); - ISFS_Close(fd); - SAFE_CLOSE(file); + SAFE_CLOSE(file); + ISFS_Close(fd); MEM2_free(status); MEM2_free(buffer); - return 1; + + return 0; } s32 Nand::__DumpNandFolder(const char *source, const char *dest) @@ -604,7 +619,8 @@ s32 Nand::__DumpNandFolder(const char *source, const char *dest) namelist *names = NULL; int cnt, i; char nsource[ISFS_MAXPATH]; - char ndest[MAX_FAT_PATH]; + char ndest[MAX_FAT_PATH]; + char tdest[MAX_FAT_PATH]; __GetNameList(source, &names, &cnt); @@ -617,41 +633,41 @@ s32 Nand::__DumpNandFolder(const char *source, const char *dest) if(!names[i].type) { - Asciify2(nsource); - snprintf(ndest, sizeof(ndest), "%s%s", dest, nsource); + __FATify(tdest, nsource); + snprintf(ndest, sizeof(ndest), "%s%s", dest, tdest); __DumpNandFile(nsource, ndest); } else { - if(!__TestNandPath(nsource)) - { - CreatePath("%s%s", dest, nsource); - __DumpNandFolder(nsource, dest); + if(!fake) + { + __FATify(tdest, nsource); + CreatePath("%s%s", dest, tdest); + FoldersDone++; } + + __DumpNandFolder(nsource, dest); } } - SAFE_FREE(names); - return 0; -} + return 0; +} void Nand::CreatePath(const char *path, ...) -{ +{ char *folder = NULL; va_list args; va_start(args, path); if((vasprintf(&folder, path, args) >= 0) && folder) { if(folder[strlen(folder)-1] == '/') - folder[strlen(folder)-1] = 0; - - Asciify2(folder); + folder[strlen(folder)-1] = 0; DIR *d; d = opendir(folder); if(!d) - { + { gprintf("Creating folder: \"%s\"\n", folder); makedir(folder); } @@ -662,19 +678,17 @@ void Nand::CreatePath(const char *path, ...) } } va_end(args); - SAFE_FREE(folder); + SAFE_FREE(folder); } -s32 Nand::DoNandDump(const char *source, const char *dest, bool dumpios, bool dumpwgs, bool dumpwsc, bool dumpwvc, bool dumpmen) -{ - n_dumpios = dumpios; +s32 Nand::DoNandDump(const char *source, const char *dest, bool dumpwgs, dump_callback_t i_dumper, void *i_data) +{ + data = i_data; + dumper = i_dumper; n_dumpwgs = dumpwgs; - n_dumpwsc = dumpwsc; - n_dumpwvc = dumpwvc; - n_dumpmen = dumpmen; - + fake = false; + showprogress = true; u32 temp = 0; - s32 ret = ISFS_ReadDir(source, NULL, &temp); if(ret < 0) { @@ -685,12 +699,38 @@ s32 Nand::DoNandDump(const char *source, const char *dest, bool dumpios, bool du __DumpNandFile(source, ndest); } else - { + { __DumpNandFolder(source, dest); - } - + } return 0; } + +s32 Nand::CalcDumpSpace(const char *source, bool dumpwgs, dump_callback_t i_dumper, void *i_data) +{ + data = i_data; + dumper = i_dumper; + n_dumpwgs = dumpwgs; + fake = true; + showprogress = true; + + u32 temp = 0; + + s32 ret = ISFS_ReadDir(source, NULL, &temp); + if(ret < 0) + __DumpNandFile(source, ""); + else + __DumpNandFolder(source, ""); + + return NandSize; +} + +void Nand::ResetCounters(void) +{ + NandSize = 0; + FilesDone = 0; + FoldersDone = 0; + NandDone = 0; +} s32 Nand::CreateConfig(const char *path) { @@ -702,6 +742,9 @@ s32 Nand::CreateConfig(const char *path) CreatePath("%s/title/00000001/00000002", path); CreatePath("%s/title/00000001/00000002/data", path); + fake = false; + showprogress = false; + bzero(cfgpath, MAX_FAT_PATH+1); bzero(settxtpath, MAX_FAT_PATH+1); diff --git a/source/channel/nand.hpp b/source/channel/nand.hpp index 25480d0e..04e8d5ca 100644 --- a/source/channel/nand.hpp +++ b/source/channel/nand.hpp @@ -23,6 +23,8 @@ #define BLOCK 2048 +typedef void (*dump_callback_t)(int dumpstat, int dumpprog, int filestat, int fileprog, int files, int folders, char *tmess, void *user_data); + /* 'NAND Device' structure */ typedef struct nandDevice { @@ -70,8 +72,10 @@ class Nand s32 CreateConfig(const char *path); s32 Do_Region_Change(string id); - s32 DoNandDump(const char *source, const char *dest, bool dumpios, bool dumpwgs, bool dumpwsc, bool dumpwvc, bool dumpmen); - + s32 DoNandDump(const char *source, const char *dest, bool dumpwgs, dump_callback_t i_dumper, void *i_data); + s32 CalcDumpSpace(const char *source, bool dumpwgs, dump_callback_t i_dumper, void *i_data); + void ResetCounters(void); + private: Nand() : MountedDevice(0), EmuDevice(REAL_NAND), Disabled(true), Partition(0), FullMode(0x100), NandPath() {} ~Nand(void){} @@ -90,20 +94,26 @@ class Nand u32 __configsetbigarray(const char *item, void *val, u32 size); u32 __configsetsetting(const char *item, const char *val); bool __FileExists(const char *path, ...); - u32 __TestNandPath(const char *path); + void __FATify(char *dst, const char *src); + s32 __Unescaped2x(const char *path); s32 __FlashNandFile(const char *source, const char *dest); s32 __DumpNandFile(const char *source, const char *dest); s32 __DumpNandFolder(const char *source, const char *dest); u32 MountedDevice; u32 EmuDevice; + u32 NandSize; + u32 NandDone; + u32 FileDone; + u32 FilesDone; + u32 FoldersDone; bool Disabled; - bool n_dumpios; bool n_dumpwgs; - bool n_dumpwsc; - bool n_dumpwvc; - bool n_dumpmen; + bool fake; + bool showprogress; + void *data; + dump_callback_t dumper; u32 Partition ATTRIBUTE_ALIGN(32); u32 FullMode ATTRIBUTE_ALIGN(32); char NandPath[32] ATTRIBUTE_ALIGN(32); diff --git a/source/defines.h b/source/defines.h index 5acf690c..911b4c5b 100644 --- a/source/defines.h +++ b/source/defines.h @@ -4,7 +4,7 @@ #define APPDATA_DIR "wiiflow" #define APPDATA_DIR2 "apps/wiiflow" -#define STDEMU_DIR "/wiiflow/nandemu" +#define STDEMU_DIR "/wiiflow/nandemu/" #define GAMES_DIR "%s:/wbfs" #define HOMEBREW_DIR "%s:/apps" #define DML_DIR "%s:/games" diff --git a/source/menu/menu.cpp b/source/menu/menu.cpp index ca08e2f8..8cf77a0d 100644 --- a/source/menu/menu.cpp +++ b/source/menu/menu.cpp @@ -1026,6 +1026,7 @@ void CMenu::_buildMenus(void) _initCategorySettingsMenu(theme); _initSystemMenu(theme); _initGameInfoMenu(theme); + _initNandEmuMenu(theme); _loadCFCfg(theme); } diff --git a/source/menu/menu.hpp b/source/menu/menu.hpp index d3bb1be5..0bc4221c 100644 --- a/source/menu/menu.hpp +++ b/source/menu/menu.hpp @@ -192,10 +192,8 @@ private: u32 m_configLblPartition; u32 m_configBtnPartitionP; u32 m_configBtnPartitionM; - u32 m_configLblEmulationVal; - u32 m_configLblEmulation; - u32 m_configBtnEmulationM; - u32 m_configBtnEmulationP; + u32 m_configLblNandEmu; + u32 m_configBtnNandEmu; u32 m_configLblUser[4]; u32 m_configAdvLblTheme; u32 m_configAdvLblCurTheme; @@ -554,6 +552,37 @@ private: u32 m_categoryBtnCats[21]; u32 m_categoryLblUser[4]; u8 m_max_categories; + // NandEmulation menu + std::string m_saveExtGameId; + bool m_nandext; + bool m_fulldump; + bool m_sgdump; + bool m_saveall; + bool m_forceext; + //int m_saveExtMode; + u32 m_nandemuLblTitle; + u32 m_nandemuBtnBack; + u32 m_nandemuLblEmulationVal; + u32 m_nandemuLblEmulation; + u32 m_nandemuBtnEmulationM; + u32 m_nandemuBtnEmulationP; + u32 m_nandemuLblSaveDump; + u32 m_nandemuBtnAll; + u32 m_nandemuBtnMissing; + u32 m_nandemuLblNandDump; + u32 m_nandemuBtnNandDump; + u32 m_nandfileLblMessage; + u32 m_nandemuLblMessage; + u32 m_nandfileLblDialog; + u32 m_nandfinLblDialog; + u32 m_nandemuLblDialog; + u32 m_nandfilePBar; + u32 m_nandemuPBar; + u32 m_nandemuBtnExtract; + u32 m_nandemuBtnDisable; + u32 m_nandemuLblInit; + u32 m_nandemuLblUser[4]; + STexture m_nandemuBg; // Zones SZone m_mainPrevZone; SZone m_mainNextZone; @@ -651,6 +680,7 @@ private: mutex_t m_mutex; wstringEx m_thrdMessage; volatile float m_thrdProgress; + volatile float m_fileProgress; volatile bool m_thrdMessageAdded; volatile bool m_gameSelected; GuiSound m_gameSound; @@ -802,6 +832,7 @@ private: void _initCategorySettingsMenu(SThemeData &theme); void _initSystemMenu(SThemeData &theme); void _initGameInfoMenu(SThemeData &theme); + void _initNandEmuMenu(CMenu::SThemeData &theme); // void _textCategorySettings(void); void _textCheatSettings(void); @@ -822,6 +853,7 @@ private: void _textWBFS(void); void _textGameSettings(void); void _textGameInfo(void); + void _textNandEmu(void); // void _hideCheatSettings(bool instant = false); void _hideError(bool instant = false); @@ -844,6 +876,7 @@ private: void _hideSystem(bool instant = false); void _hideGameInfo(bool instant = false); void _hideCheatDownload(bool instant = false); + void _hideNandEmu(bool instant = false); // void _showError(void); void _showMain(void); @@ -872,6 +905,7 @@ private: void _updateBg(void); void _drawBg(void); void _updateText(void); + void _showNandEmu(void); // void _config(int page); int _config1(void); @@ -880,6 +914,9 @@ private: int _config4(void); int _configAdv(void); int _configSnd(void); + int _NandEmuCfg(void); + int _AutoCreateNand(void); + int _AutoExtractSave(string gameId); void _game(bool launch = false); void _download(std::string gameId = std::string()); bool _code(char code[4], bool erase = false); @@ -950,6 +987,7 @@ private: wstringEx _getNoticeTranslation(int sorting, wstringEx curLetter); // void _setThrdMsg(const wstringEx &msg, float progress); + void _setDumpMsg(const wstringEx &msg, float progress, float fileprog); int _coverDownloader(bool missingOnly); static int _coverDownloaderAll(CMenu *m); static int _coverDownloaderMissing(CMenu *m); @@ -967,12 +1005,21 @@ private: void _getGrabStatus(void); static void _addDiscProgress(int status, int total, void *user_data); static void _Messenger(int message, int info, char *cinfo, void *user_data); + static void _ShowProgress(int dumpstat, int dumpprog, int filestat, int fileprog, int files, int folders, char *tmess, void *user_data); static int _gameInstaller(void *obj); static int _GCgameInstaller(void *obj); static int _GCcopyGame(void *obj); - float m_progress; + float m_progress; + float m_fprogress; + int m_fileprog; + int m_filesize; + int m_dumpsize; + int m_filesdone; + int m_foldersdone; + int m_nandexentry; wstringEx _optBoolToString(int b); void _stopSounds(void); + static int _NandDumper(void *obj); static u32 _downloadCheatFileAsync(void *obj); @@ -1002,6 +1049,7 @@ private: static const SOption _vidModePatch[4]; static const SOption _hooktype[8]; static const SOption _exitTo[6]; + static const SOption _DumpMode[4]; static std::map _installed_cios; typedef std::map::iterator CIOSItr; static int _version[9]; diff --git a/source/menu/menu_config.cpp b/source/menu/menu_config.cpp index b4f302bf..6922eaec 100644 --- a/source/menu/menu_config.cpp +++ b/source/menu/menu_config.cpp @@ -6,54 +6,11 @@ #include "loader/alt_ios.h" #include "gecko/gecko.h" - using namespace std; -static inline int loopNum(int i, int s) -{ - return i < 0 ? (s - (-i % s)) % s : i % s; -} - const int CMenu::_nbCfgPages = 6; static const int g_curPage = 1; -void CMenu::_enableNandEmu(bool fromconfig) -{ - bool disable = true; - int i = m_current_view == COVERFLOW_CHANNEL && min(max(0, m_cfg.getInt("NAND", "emulation", 0)), (int)ARRAY_SIZE(CMenu::_NandEmu) - 1); - gprintf("i: %i\n",i); - if (i>0 || m_current_view != COVERFLOW_CHANNEL) - disable = false; - if(!disable) - { - Nand::Instance()->Disable_Emu(); - bool isD2XnewerThanV6 = false; - iosinfo_t * iosInfo = cIOSInfo::GetInfo(mainIOS); - if (iosInfo->version > 6) - isD2XnewerThanV6 = true; - if(m_current_view == COVERFLOW_CHANNEL && m_cfg.getInt("NAND", "emulation", 0) > 0) - Nand::Instance()->Enable_Emu(); - u8 limiter = 0; - s8 direction = m_btnMgr.selected(m_configBtnPartitionP) ? 1 : -1; - if (!fromconfig) - direction = 0; - currentPartition = loopNum(currentPartition + direction, (int)USB8); - while(!DeviceHandler::Instance()->IsInserted(currentPartition) || - ((m_current_view == COVERFLOW_CHANNEL || m_current_view == COVERFLOW_EMU) && (DeviceHandler::Instance()->GetFSType(currentPartition) != PART_FS_FAT || - (!isD2XnewerThanV6 && DeviceHandler::Instance()->PathToDriveType(m_appDir.c_str()) == currentPartition) || - (!isD2XnewerThanV6 && DeviceHandler::Instance()->PathToDriveType(m_dataDir.c_str()) == currentPartition))) || - ((m_current_view == COVERFLOW_HOMEBREW || m_current_view == COVERFLOW_DML) && DeviceHandler::Instance()->GetFSType(currentPartition) == PART_FS_WBFS)) - { - currentPartition = loopNum(currentPartition + direction, (int)USB8); - if (limiter > 10) break; - limiter++; - } - - gprintf("Next item: %s\n", DeviceName[currentPartition]); - m_cfg.setInt(_domainFromView(), "partition", currentPartition); - } -} - void CMenu::_hideConfig(bool instant) { m_btnMgr.hide(m_configLblTitle, instant); @@ -71,10 +28,8 @@ void CMenu::_hideConfig(bool instant) m_btnMgr.hide(m_configLblParental, instant); m_btnMgr.hide(m_configBtnUnlock, instant); m_btnMgr.hide(m_configBtnSetCode, instant); - m_btnMgr.hide(m_configLblEmulationVal, instant); - m_btnMgr.hide(m_configLblEmulation, instant); - m_btnMgr.hide(m_configBtnEmulationP, instant); - m_btnMgr.hide(m_configBtnEmulationM, instant); + m_btnMgr.hide(m_configLblNandEmu, instant); + m_btnMgr.hide(m_configBtnNandEmu, instant); for (u32 i = 0; i < ARRAY_SIZE(m_configLblUser); ++i) if (m_configLblUser[i] != -1u) m_btnMgr.hide(m_configLblUser[i], instant); @@ -118,25 +73,8 @@ void CMenu::_showConfig(void) m_btnMgr.setText(m_configLblPage, wfmt(L"%i / %i", g_curPage, m_locked ? g_curPage + 1 : CMenu::_nbCfgPages)); - if ((m_current_view == COVERFLOW_CHANNEL || m_current_view == COVERFLOW_USB) && !m_locked) - { - m_btnMgr.show(m_configLblEmulation); - m_btnMgr.show(m_configLblEmulationVal); - m_btnMgr.show(m_configBtnEmulationP); - m_btnMgr.show(m_configBtnEmulationM); - if (m_current_view == COVERFLOW_CHANNEL) - { - m_btnMgr.setText(m_configLblEmulation, _t("cfg12", L"NAND Emulation")); - i = min(max(0, m_cfg.getInt("NAND", "emulation", 0)), (int)ARRAY_SIZE(CMenu::_NandEmu) - 1); - m_btnMgr.setText(m_configLblEmulationVal, _t(CMenu::_NandEmu[i].id, CMenu::_NandEmu[i].text)); - } - else if (m_current_view == COVERFLOW_USB) - { - m_btnMgr.setText(m_configLblEmulation, _t("cfgg24", L"Savegame Emulation")); - i = min(max(0, m_cfg.getInt("GAMES", "save_emulation", 0)), (int)ARRAY_SIZE(CMenu::_GlobalSaveEmu) - 1); - m_btnMgr.setText(m_configLblEmulationVal, _t(CMenu::_GlobalSaveEmu[i].id, CMenu::_GlobalSaveEmu[i].text)); - } - } + m_btnMgr.show(m_configLblNandEmu); + m_btnMgr.show(m_configBtnNandEmu); } void CMenu::_config(int page) @@ -245,14 +183,13 @@ int CMenu::_config1(void) _enableNandEmu(true); _showConfig(); } - else if (!m_locked && (m_btnMgr.selected(m_configBtnEmulationP) || m_btnMgr.selected(m_configBtnEmulationM))) + else if (!m_locked && m_btnMgr.selected(m_configBtnNandEmu)) { - s8 direction = m_btnMgr.selected(m_configBtnEmulationP) ? 1 : -1; - if (m_current_view == COVERFLOW_CHANNEL) - m_cfg.setInt("NAND", "emulation", (int)loopNum((u32)m_cfg.getInt("NAND", "emulation", 0) + direction, ARRAY_SIZE(CMenu::_NandEmu))); - else if (m_current_view == COVERFLOW_USB) - m_cfg.setInt("GAMES", "save_emulation", (int)loopNum((u32)m_cfg.getInt("GAMES", "save_emulation", 0) + direction, ARRAY_SIZE(CMenu::_GlobalSaveEmu))); + m_cf.stopCoverLoader(true); + _hideConfig(); + _NandEmuCfg(); _showConfig(); + m_cf.startCoverLoader(); } } } @@ -295,11 +232,8 @@ void CMenu::_initConfigMenu(CMenu::SThemeData &theme) m_configLblPartition = _addLabel(theme, "CONFIG/PARTITION_BTN", theme.btnFont, L"", 456, 250, 88, 56, theme.btnFontColor, FTGX_JUSTIFY_CENTER | FTGX_ALIGN_MIDDLE, theme.btnTexC); m_configBtnPartitionM = _addPicButton(theme, "CONFIG/PARTITION_MINUS", theme.btnTexMinus, theme.btnTexMinusS, 400, 250, 56, 56); m_configBtnPartitionP = _addPicButton(theme, "CONFIG/PARTITION_PLUS", theme.btnTexPlus, theme.btnTexPlusS, 544, 250, 56, 56); - m_configLblEmulation = _addLabel(theme, "CONFIG/EMU_SAVE", theme.lblFont, L"", 40, 310, 340, 56, theme.lblFontColor, FTGX_JUSTIFY_LEFT | FTGX_ALIGN_MIDDLE); - m_configLblEmulationVal = _addLabel(theme, "CONFIG/EMU_SAVE_BTN_GLOBAL", theme.btnFont, L"", 456, 310, 88, 56, theme.btnFontColor, FTGX_JUSTIFY_CENTER | FTGX_ALIGN_MIDDLE, theme.btnTexC); - m_configBtnEmulationM = _addPicButton(theme, "CONFIG/EMU_SAVE_MINUS", theme.btnTexMinus, theme.btnTexMinusS, 400, 310, 56, 56); - m_configBtnEmulationP = _addPicButton(theme, "CONFIG/EMU_SAVE_PLUS", theme.btnTexPlus, theme.btnTexPlusS, 544, 310, 56, 56); - m_configLblPage = _addLabel(theme, "CONFIG/PAGE_BTN", theme.btnFont, L"", 76, 400, 80, 56, theme.btnFontColor, FTGX_JUSTIFY_CENTER | FTGX_ALIGN_MIDDLE, theme.btnTexC); + m_configLblNandEmu = _addLabel(theme, "CONFIG/NANDEMU", theme.lblFont, L"", 40, 310, 340, 56, theme.lblFontColor, FTGX_JUSTIFY_LEFT | FTGX_ALIGN_MIDDLE); + m_configBtnNandEmu = _addButton(theme, "CONFIG/NANDEMU_BTN", theme.btnFont, L"", 400, 310, 200, 56, theme.btnFontColor);m_configLblPage = _addLabel(theme, "CONFIG/PAGE_BTN", theme.btnFont, L"", 76, 400, 80, 56, theme.btnFontColor, FTGX_JUSTIFY_CENTER | FTGX_ALIGN_MIDDLE, theme.btnTexC); m_configBtnPageM = _addPicButton(theme, "CONFIG/PAGE_MINUS", theme.btnTexMinus, theme.btnTexMinusS, 20, 400, 56, 56); m_configBtnPageP = _addPicButton(theme, "CONFIG/PAGE_PLUS", theme.btnTexPlus, theme.btnTexPlusS, 156, 400, 56, 56); m_configBtnBack = _addButton(theme, "CONFIG/BACK_BTN", theme.btnFont, L"", 420, 400, 200, 56, theme.btnFontColor); @@ -315,10 +249,8 @@ void CMenu::_initConfigMenu(CMenu::SThemeData &theme) _setHideAnim(m_configLblPartition, "CONFIG/PARTITION_BTN", 0, 0, 1.f, -1.f); _setHideAnim(m_configBtnPartitionM, "CONFIG/PARTITION_MINUS", 0, 0, 1.f, -1.f); _setHideAnim(m_configBtnPartitionP, "CONFIG/PARTITION_PLUS", 0, 0, 1.f, -1.f); - _setHideAnim(m_configLblEmulation, "CONFIG/EMU_SAVE", 100, 0, -2.f, 0.f); - _setHideAnim(m_configLblEmulationVal, "CONFIG/EMU_SAVE_BTN_GLOBAL", 0, 0, 1.f, -1.f); - _setHideAnim(m_configBtnEmulationM, "CONFIG/EMU_SAVE_MINUS", 0, 0, 1.f, -1.f); - _setHideAnim(m_configBtnEmulationP, "CONFIG/EMU_SAVE_PLUS", 0, 0, 1.f, -1.f); + _setHideAnim(m_configLblNandEmu, "CONFIG/NANDEMU", 100, 0, -2.f, 0.f); + _setHideAnim(m_configBtnNandEmu, "CONFIG/NANDEMU_BTN", 0, 0, 1.f, -1.f); _setHideAnim(m_configBtnBack, "CONFIG/BACK_BTN", 0, 0, -2.f, 0.f); _setHideAnim(m_configLblPage, "CONFIG/PAGE_BTN", 0, 0, 1.f, -1.f); _setHideAnim(m_configBtnPageM, "CONFIG/PAGE_MINUS", 0, 0, 1.f, -1.f); @@ -335,7 +267,8 @@ void CMenu::_textConfig(void) m_btnMgr.setText(m_configLblParental, _t("cfg5", L"Parental control")); m_btnMgr.setText(m_configBtnUnlock, _t("cfg6", L"Unlock")); m_btnMgr.setText(m_configBtnSetCode, _t("cfg7", L"Set code")); - m_btnMgr.setText(m_configLblPartitionName, _t("cfgp1", L"Game Partition")); m_btnMgr.setText(m_configBtnBack, _t("cfg10", L"Back")); + m_btnMgr.setText(m_configLblNandEmu, _t("cfg13", L"Nand emulation settings")); + m_btnMgr.setText(m_configBtnNandEmu, _t("cfg14", L"Set")); } diff --git a/source/menu/menu_game.cpp b/source/menu/menu_game.cpp index 57ad56ca..06682ffe 100644 --- a/source/menu/menu_game.cpp +++ b/source/menu/menu_game.cpp @@ -204,6 +204,7 @@ const CMenu::SOption CMenu::_hooktype[8] = { { "hooktype6", L"OSSleepThread" }, { "hooktype7", L"AXNextFrame" }, }; + /* 0 No Hook 1 VBI @@ -215,6 +216,13 @@ const CMenu::SOption CMenu::_hooktype[8] = { 7 AXNextFrame Hook */ +const CMenu::SOption CMenu::_DumpMode[4] = { + { "DumpNAll", L"Nand All" }, + { "DumpNMss", L"Nand Missing" }, + { "DumpLAll", L"List All" }, + { "DumpLMss", L"List Missing" }, +}; + std::map CMenu::_installed_cios; u8 banner_title[84]; @@ -1054,7 +1062,7 @@ void CMenu::_launchGame(dir_discHdr *hdr, bool dvd) int emuPartition = m_cfg.getInt("GAMES", "savepartition", -1); if(emuPartition == -1) - emuPartition = m_cfg.getInt("NAND", "partition", 0); + emuPartition = m_cfg.getInt("NAND", "partition", 0); string emuPath = m_cfg.getString("GAMES", "savepath", m_cfg.getString("NAND", "path", "")); @@ -1070,7 +1078,28 @@ void CMenu::_launchGame(dir_discHdr *hdr, bool dvd) emuSave = 0; if(!dvd && emuSave) - { + { + bool emuPartIsValid = false; + for(u8 i = emuPartition; i <= USB8; ++i) + { + if(!DeviceHandler::Instance()->IsInserted(emuPartition) || DeviceHandler::Instance()->GetFSType(emuPartition) != PART_FS_FAT) + { + emuPartition++; + continue; + } + else + { + emuPartIsValid = true; + break; + } + } + + if(!emuPartIsValid) + { + error(sfmt("No valid FAT partition found for nandemulation!")); + return; + } + bool createnand = false; char basepath[64]; if(emuPath.size() == 0) @@ -1102,21 +1131,23 @@ void CMenu::_launchGame(dir_discHdr *hdr, bool dvd) } } } - + if(createnand) { -#ifdef ENABLEDUMPER - bool dumpios = m_cfg.getBool("NAND", "nanddumpios", false); - bool dumpgs = m_cfg.getBool("NAND", "nanddumpgamesaves", false); - bool dumpsc = m_cfg.getBool("NAND", "nanddumpsyschannels", false); - bool dumpwvc = m_cfg.getBool("NAND", "nanddumpwwchannels", true); - bool dumpmen = m_cfg.getBool("NAND", "nanddumpsysmenu", false); - Nand::Instance()->DoNandDump("/", basepath, dumpios, dumpgs, dumpsc, dumpwvc, dumpmen); -#endif - } + _hideWaitMessage(); + _AutoCreateNand(); + _showWaitMessage(); + } if(emuSave == 2 || emuSave > 3) { + if(emuSave == 2) + { + m_forceext = false; + _hideWaitMessage(); + _AutoExtractSave(id); + _showWaitMessage(); + } CreateSavePath(basepath, hdr); } if(emuSave > 2) diff --git a/source/menu/menu_main.cpp b/source/menu/menu_main.cpp index 0945abfe..1c710e1a 100644 --- a/source/menu/menu_main.cpp +++ b/source/menu/menu_main.cpp @@ -143,9 +143,39 @@ void CMenu::_showMain(void) if (m_gameList.empty()) { - m_btnMgr.show(m_mainBtnInit); - m_btnMgr.show(m_mainBtnInit2); - m_btnMgr.show(m_mainLblInit); + switch(m_current_view) + { + case COVERFLOW_USB: + case COVERFLOW_DML: + m_btnMgr.setText(m_mainLblInit, _t("main2", L"Welcome to WiiFlow. I have not found any games. Click Install to install games, or Select partition to select your partition type."), true); + m_btnMgr.show(m_mainBtnInit); + m_btnMgr.show(m_mainBtnInit2); + m_btnMgr.show(m_mainLblInit); + break; + case COVERFLOW_CHANNEL: + if(!m_cfg.getBool("NAND", "disable", true)) + { + Nand::Instance()->Disable_Emu(); + _hideMain(); + if(!_AutoCreateNand()) + m_cfg.setBool("NAND", "disable", true); + + _loadList(); + _showMain(); + _initCF(); + } + break; + case COVERFLOW_HOMEBREW: + m_btnMgr.setText(m_mainLblInit, _t("main4", L"Welcome to WiiFlow. I have not found any homebrew apps. Select partition to select your partition type."), true); + m_btnMgr.show(m_mainBtnInit2); + m_btnMgr.show(m_mainLblInit); + break; + case COVERFLOW_EMU: + m_btnMgr.setText(m_mainLblInit, _t("main5", L"Welcome to WiiFlow. I have not found any emulator plugins or games. Select partition to select your partition type."), true); + m_btnMgr.show(m_mainBtnInit2); + m_btnMgr.show(m_mainLblInit); + break; + } } } @@ -913,7 +943,7 @@ void CMenu::_textMain(void) { m_btnMgr.setText(m_mainBtnInit, _t("main1", L"Install Game")); m_btnMgr.setText(m_mainBtnInit2, _t("main3", L"Select Partition")); - m_btnMgr.setText(m_mainLblInit, _t("main2", L"Welcome to WiiFlow. I have not found any games. Click Install to install games, or Select partition to select your partition type."), true); + //m_btnMgr.setText(m_mainLblInit, _t("main2", L"Welcome to WiiFlow. I have not found any games. Click Install to install games, or Select partition to select your partition type."), true); } wstringEx CMenu::_getNoticeTranslation(int sorting, wstringEx curLetter) diff --git a/source/menu/menu_nandemu.cpp b/source/menu/menu_nandemu.cpp new file mode 100644 index 00000000..fd017ecb --- /dev/null +++ b/source/menu/menu_nandemu.cpp @@ -0,0 +1,640 @@ + +#include "menu.hpp" +#include "nand.hpp" +#include "sys.h" +#include "loader/cios.hpp" +#include "loader/alt_ios.h" +#include "lockMutex.hpp" +#include "gecko/gecko.h" +#include "defines.h" + +using namespace std; + +static inline int loopNum(int i, int s) +{ + return i < 0 ? (s - (-i % s)) % s : i % s; +} + +static bool _saveExcists(const char *path) +{ + DIR *d; + d = opendir(path); + if(!d) + { + return false; + } + else + { + closedir(d); + return true; + } +} + +static bool _nandSaveExcists(const char *npath) +{ + u32 temp = 0; + + s32 ret = ISFS_ReadDir(npath, NULL, &temp); + if(ret < 0) + return false; + + return true; +} + +void CMenu::_enableNandEmu(bool fromconfig) +{ + bool disable = true; + int i = m_current_view == COVERFLOW_CHANNEL && min(max(0, m_cfg.getInt("NAND", "emulation", 0)), (int)ARRAY_SIZE(CMenu::_NandEmu) - 1); + gprintf("i: %i\n",i); + if (i>0 || m_current_view != COVERFLOW_CHANNEL) + disable = false; + if(!disable) + { + Nand::Instance()->Disable_Emu(); + bool isD2XnewerThanV6 = false; + iosinfo_t * iosInfo = cIOSInfo::GetInfo(mainIOS); + if (iosInfo->version > 6) + isD2XnewerThanV6 = true; + if(m_current_view == COVERFLOW_CHANNEL && m_cfg.getInt("NAND", "emulation", 0) > 0) + Nand::Instance()->Enable_Emu(); + u8 limiter = 0; + s8 direction = m_btnMgr.selected(m_configBtnPartitionP) ? 1 : -1; + if (!fromconfig) + direction = 0; + currentPartition = loopNum(currentPartition + direction, (int)USB8); + while(!DeviceHandler::Instance()->IsInserted(currentPartition) || + (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_dataDir.c_str()) == currentPartition))) || + ((m_current_view == COVERFLOW_HOMEBREW || m_current_view == COVERFLOW_DML) && DeviceHandler::Instance()->GetFSType(currentPartition) == PART_FS_WBFS)) + { + currentPartition = loopNum(currentPartition + direction, (int)USB8); + if (limiter > 10) break; + limiter++; + } + + gprintf("Next item: %s\n", DeviceName[currentPartition]); + m_cfg.setInt(_domainFromView(), "partition", currentPartition); + } +} + +void CMenu::_setDumpMsg(const wstringEx &msg, float totprog, float fileprog) +{ + if(m_thrdStop) return; + if(msg != L"...") m_thrdMessage = msg; + m_thrdMessageAdded = true; + m_thrdProgress = totprog; + m_fileProgress = fileprog; +} + +void CMenu::_ShowProgress(int dumpstat, int dumpprog, int filesize, int fileprog, int files, int folders, char *tmess, void *user_data) +{ + CMenu &m = *(CMenu *)user_data; + m.m_progress = dumpprog == 0 ? 0.f : (float)dumpstat / (float)dumpprog; + m.m_fprogress = filesize == 0 ? 0.f : (float)fileprog / (float)filesize; + m.m_fileprog = fileprog; + m.m_filesize = filesize; + m.m_filesdone = files; + m.m_foldersdone = folders; + LWP_MutexLock(m.m_mutex); + if(m.m_nandext) + m._setDumpMsg(wfmt(m._fmt("cfgne9", L"Current file: %s"), tmess), m.m_progress, m.m_fprogress); + else + m._setDumpMsg(L"...", m.m_progress, m.m_fprogress); + LWP_MutexUnlock(m.m_mutex); +} + +void CMenu::_hideNandEmu(bool instant) +{ + m_btnMgr.hide(m_nandemuLblTitle, instant); + m_btnMgr.hide(m_nandemuBtnBack, instant); + m_btnMgr.hide(m_nandfilePBar, instant); + m_btnMgr.hide(m_nandemuPBar, instant); + m_btnMgr.hide(m_nandfileLblMessage, instant); + m_btnMgr.hide(m_nandemuLblMessage, instant); + m_btnMgr.hide(m_nandfileLblDialog, instant); + m_btnMgr.hide(m_nandemuLblDialog, instant); + m_btnMgr.hide(m_nandfinLblDialog, instant); + m_btnMgr.hide(m_nandemuLblEmulationVal, instant); + m_btnMgr.hide(m_nandemuLblEmulation, instant); + m_btnMgr.hide(m_nandemuBtnEmulationP, instant); + m_btnMgr.hide(m_nandemuBtnEmulationM, instant); + m_btnMgr.hide(m_nandemuLblSaveDump, instant); + m_btnMgr.hide(m_nandemuBtnAll, instant); + m_btnMgr.hide(m_nandemuBtnMissing, instant); + m_btnMgr.hide(m_nandemuLblNandDump, instant); + m_btnMgr.hide(m_nandemuBtnNandDump, instant); + m_btnMgr.hide(m_nandemuBtnExtract, instant); + m_btnMgr.hide(m_nandemuBtnDisable, instant); + m_btnMgr.hide(m_nandemuLblInit, instant); +} + +void CMenu::_showNandEmu(void) +{ + _setBg(m_nandemuBg, m_nandemuBg); + m_btnMgr.setText(m_nandemuLblTitle, _t("cfgne10", L"Nand emulation settings")); + m_btnMgr.show(m_nandemuLblTitle); + m_btnMgr.show(m_nandemuBtnBack); + int i; + if((m_current_view == COVERFLOW_CHANNEL || m_current_view == COVERFLOW_USB) && !m_locked) + { + m_btnMgr.show(m_nandemuLblEmulation); + m_btnMgr.show(m_nandemuLblEmulationVal); + m_btnMgr.show(m_nandemuBtnEmulationP); + m_btnMgr.show(m_nandemuBtnEmulationM); + m_btnMgr.show(m_nandemuLblSaveDump); + m_btnMgr.show(m_nandemuBtnAll); + m_btnMgr.show(m_nandemuBtnMissing); + m_btnMgr.show(m_nandemuLblNandDump); + m_btnMgr.show(m_nandemuBtnNandDump); + if (m_current_view == COVERFLOW_CHANNEL) + { + i = min(max(0, m_cfg.getInt("NAND", "emulation", 0)), (int)ARRAY_SIZE(CMenu::_NandEmu) - 1); + m_btnMgr.setText(m_nandemuLblEmulationVal, _t(CMenu::_NandEmu[i].id, CMenu::_NandEmu[i].text)); + } + else if (m_current_view == COVERFLOW_USB) + { + i = min(max(0, m_cfg.getInt("GAMES", "save_emulation", 0)), (int)ARRAY_SIZE(CMenu::_GlobalSaveEmu) - 1); + m_btnMgr.setText(m_nandemuLblEmulationVal, _t(CMenu::_GlobalSaveEmu[i].id, CMenu::_GlobalSaveEmu[i].text)); + } + } +} + +int CMenu::_NandEmuCfg(void) +{ + lwp_t thread = 0; + SetupInput(); + _showNandEmu(); + + m_thrdStop = false; + m_thrdMessageAdded = false; + m_nandext = false; + + while(true) + { + _mainLoopCommon(false, m_thrdWorking); + if((BTN_HOME_PRESSED || BTN_B_PRESSED) && !m_thrdWorking) + break; + else if(BTN_UP_PRESSED) + m_btnMgr.up(); + else if(BTN_DOWN_PRESSED) + m_btnMgr.down(); + else if (BTN_A_PRESSED && (m_btnMgr.selected(m_nandemuBtnEmulationP) || m_btnMgr.selected(m_nandemuBtnEmulationM))) + { + s8 direction = m_btnMgr.selected(m_nandemuBtnEmulationP) ? 1 : -1; + if(m_current_view == COVERFLOW_CHANNEL) + m_cfg.setInt("NAND", "emulation", (int)loopNum((u32)m_cfg.getInt("NAND", "emulation", 0) + direction, ARRAY_SIZE(CMenu::_NandEmu))); + else if(m_current_view == COVERFLOW_USB) + m_cfg.setInt("GAMES", "save_emulation", (int)loopNum((u32)m_cfg.getInt("GAMES", "save_emulation", 0) + direction, ARRAY_SIZE(CMenu::_GlobalSaveEmu))); + _showNandEmu(); + } + else if(BTN_A_PRESSED && (m_btnMgr.selected(m_nandemuBtnNandDump) || m_btnMgr.selected(m_nandemuBtnAll) || m_btnMgr.selected(m_nandemuBtnMissing))) + { + m_fulldump = m_btnMgr.selected(m_nandemuBtnNandDump) ? true : false; + m_saveall = m_btnMgr.selected(m_nandemuBtnAll) ? true : false; + m_btnMgr.hide(m_nandemuBtnBack); + m_btnMgr.hide(m_nandemuLblEmulationVal); + m_btnMgr.hide(m_nandemuLblEmulation); + m_btnMgr.hide(m_nandemuBtnEmulationP); + m_btnMgr.hide(m_nandemuBtnEmulationM); + m_btnMgr.hide(m_nandemuLblSaveDump); + m_btnMgr.hide(m_nandemuBtnAll); + m_btnMgr.hide(m_nandemuBtnMissing); + m_btnMgr.hide(m_nandemuLblNandDump); + m_btnMgr.hide(m_nandemuBtnNandDump); + m_btnMgr.show(m_nandfilePBar); + m_btnMgr.show(m_nandemuPBar); + m_btnMgr.show(m_nandfileLblMessage); + m_btnMgr.show(m_nandemuLblMessage); + m_btnMgr.show(m_nandfileLblDialog); + m_btnMgr.show(m_nandemuLblDialog); + m_btnMgr.setText(m_nandemuLblMessage, L""); + m_btnMgr.setText(m_nandfileLblMessage, L""); + m_btnMgr.setText(m_nandemuLblDialog, _t("cfgne11", L"Overall progress:")); + if(m_fulldump) + m_btnMgr.setText(m_nandemuLblTitle, _t("cfgne12", L"Nand extractor")); + else + m_btnMgr.setText(m_nandemuLblTitle, _t("cfgne13", L"Game save extractor")); + m_thrdStop = false; + m_thrdProgress = 0.f; + m_thrdWorking = true; + LWP_CreateThread(&thread, (void *(*)(void *))CMenu::_NandDumper, (void *)this, 0, 32768, 40); + } + else if(BTN_A_PRESSED && (m_btnMgr.selected(m_nandemuBtnBack))) + { + m_cfg.save(); + break; + } + + if (m_thrdMessageAdded) + { + LockMutex lock(m_mutex); + m_thrdMessageAdded = false; + if (!m_thrdMessage.empty()) + m_btnMgr.setText(m_nandfileLblDialog, m_thrdMessage); + m_btnMgr.setProgress(m_nandfilePBar, m_fileProgress); + m_btnMgr.setProgress(m_nandemuPBar, m_thrdProgress); + m_btnMgr.setText(m_nandfileLblMessage, wfmt(_fmt("fileprogress", L"%d / %dkb"), m_fileprog/0x400, m_filesize/0x400)); + m_btnMgr.setText(m_nandemuLblMessage, wfmt(_fmt("dumpprogress", L"%i%%"), (int)(m_thrdProgress*100.f))); + + if (!m_thrdWorking) + { + + if(m_sgdump) + m_btnMgr.setText(m_nandfinLblDialog, wfmt(_fmt("cfgne14", L"Extracted: %d saves / %d files / %d folders"), m_nandexentry, m_filesdone, m_foldersdone)); + else + m_btnMgr.setText(m_nandfinLblDialog, wfmt(_fmt("cfgne15", L"Extracted: %d files / %d folders"), m_filesdone, m_foldersdone)); + if(m_dumpsize/0x400 > 0x270f) + m_btnMgr.setText(m_nandemuLblDialog, wfmt(_fmt("cfgne16", L"Total size: %uMb (%d blocks)"), (m_dumpsize/0x100000), (m_dumpsize/0x8000)>>2)); + else + m_btnMgr.setText(m_nandemuLblDialog, wfmt(_fmt("cfgne17", L"Total size: %ukb (%d blocks)"), (m_dumpsize/0x400), (m_dumpsize/0x8000)>>2)); + + + m_btnMgr.show(m_nandemuBtnBack); + m_btnMgr.show(m_nandfinLblDialog); + } + } + } + _hideNandEmu(); + return 0; +} + +int CMenu::_AutoExtractSave(string gameId) +{ + int emuPartition = m_cfg.getInt("GAMES", "savepartition", m_cfg.getInt("NAND", "partition", 0)); + int savePath = gameId.c_str()[0] << 24 | gameId.c_str()[1] << 16 | gameId.c_str()[2] << 8 | gameId.c_str()[3]; + string npath = sfmt("/title/00010000/%x", savePath); + string path = sfmt("%s:%s/title/00010000/%x", DeviceName[emuPartition], m_cfg.getString("GAMES", "savepath", m_cfg.getString("NAND", "path", "")).c_str(), savePath); + + if(!_nandSaveExcists(npath.c_str()) || (!m_forceext && _saveExcists(path.c_str()))) + return 0; + + lwp_t thread = 0; + SetupInput(); + m_thrdStop = false; + m_thrdMessageAdded = false; + m_nandext = false; + + if(!m_forceext) + { + m_btnMgr.setText(m_nandemuBtnExtract, _t("cfgne24", L"Extract save")); + m_btnMgr.setText(m_nandemuBtnDisable, _t("cfgne25", L"Create new save")); + m_btnMgr.setText(m_nandemuLblInit, _t("cfgne26", L"A save file for this game was created on real nand. Extract excisting safe file from real nand or create new file for nandemulation?")); + m_btnMgr.show(m_nandemuBtnExtract); + m_btnMgr.show(m_nandemuBtnDisable); + m_btnMgr.show(m_nandemuLblInit); + } + + m_saveExtGameId = gameId; + + while(true) + { + _mainLoopCommon(false, m_thrdWorking); + if((BTN_A_PRESSED && (m_btnMgr.selected(m_nandemuBtnExtract))) || m_forceext) + { + m_forceext = false; + m_fulldump = false; + m_btnMgr.hide(m_nandemuBtnExtract); + m_btnMgr.hide(m_nandemuBtnDisable); + m_btnMgr.hide(m_nandemuLblInit); + m_btnMgr.show(m_nandemuLblTitle); + m_btnMgr.show(m_nandfilePBar); + m_btnMgr.show(m_nandemuPBar); + m_btnMgr.show(m_nandfileLblMessage); + m_btnMgr.show(m_nandemuLblMessage); + m_btnMgr.show(m_nandfileLblDialog); + m_btnMgr.show(m_nandemuLblDialog); + m_btnMgr.setText(m_nandemuLblMessage, L""); + m_btnMgr.setText(m_nandfileLblMessage, L""); + m_btnMgr.setText(m_nandemuLblDialog, _t("cfgne11", L"Overall progress:")); + m_btnMgr.setText(m_nandemuLblTitle, _t("cfgne13", L"Game save extractor")); + m_thrdStop = false; + m_thrdProgress = 0.f; + m_thrdWorking = true; + LWP_CreateThread(&thread, (void *(*)(void *))CMenu::_NandDumper, (void *)this, 0, 32768, 40); + } + if(BTN_A_PRESSED && (m_btnMgr.selected(m_nandemuBtnDisable))) + { + _hideNandEmu(); + return 0; + } + + if(m_thrdMessageAdded) + { + LockMutex lock(m_mutex); + m_thrdMessageAdded = false; + if (!m_thrdMessage.empty()) + m_btnMgr.setText(m_nandfileLblDialog, m_thrdMessage); + m_btnMgr.setProgress(m_nandfilePBar, m_fileProgress); + m_btnMgr.setProgress(m_nandemuPBar, m_thrdProgress); + m_btnMgr.setText(m_nandfileLblMessage, wfmt(_fmt("fileprogress", L"%d / %dkb"), m_fileprog/0x400, m_filesize/0x400)); + m_btnMgr.setText(m_nandemuLblMessage, wfmt(_fmt("dumpprogress", L"%i%%"), (int)(m_thrdProgress*100.f))); + + if (!m_thrdWorking) + { + m_btnMgr.setText(m_nandfinLblDialog, wfmt(_fmt("cfgne14", L"Extracted: %d saves / %d files / %d folders"), m_nandexentry, m_filesdone, m_foldersdone)); + if(m_dumpsize/0x400 > 0x270f) + m_btnMgr.setText(m_nandemuLblDialog, wfmt(_fmt("cfgne16", L"Total size: %uMb (%d blocks)"), (m_dumpsize/0x100000), (m_dumpsize/0x8000)>>2)); + else + m_btnMgr.setText(m_nandemuLblDialog, wfmt(_fmt("cfgne17", L"Total size: %ukb (%d blocks)"), (m_dumpsize/0x400), (m_dumpsize/0x8000)>>2)); + + _hideNandEmu(); + return 1; + } + } + } + _hideNandEmu(); + return 0; +} + +int CMenu::_AutoCreateNand(void) +{ + lwp_t thread = 0; + SetupInput(); + m_thrdStop = false; + m_thrdMessageAdded = false; + m_nandext = false; + + m_btnMgr.setText(m_nandemuBtnExtract, _t("cfgne5", L"Extract nand")); + m_btnMgr.setText(m_nandemuBtnDisable, _t("cfgne22", L"Disable nandemulation")); + m_btnMgr.setText(m_nandemuLblInit, _t("cfgne23", L"Welcome to WiiFlow. I have not found a valid nand for nand emulation. Click Extract to extract your nand, or click disable to disable nand emulation.")); + m_btnMgr.show(m_nandemuBtnExtract); + m_btnMgr.show(m_nandemuBtnDisable); + m_btnMgr.show(m_nandemuLblInit); + + while(true) + { + _mainLoopCommon(false, m_thrdWorking); + if(BTN_A_PRESSED && (m_btnMgr.selected(m_nandemuBtnExtract))) + { + m_fulldump = true; + m_btnMgr.hide(m_nandemuBtnExtract); + m_btnMgr.hide(m_nandemuBtnDisable); + m_btnMgr.hide(m_nandemuLblInit); + m_btnMgr.show(m_nandemuLblTitle); + m_btnMgr.show(m_nandfilePBar); + m_btnMgr.show(m_nandemuPBar); + m_btnMgr.show(m_nandfileLblMessage); + m_btnMgr.show(m_nandemuLblMessage); + m_btnMgr.show(m_nandfileLblDialog); + m_btnMgr.show(m_nandemuLblDialog); + m_btnMgr.setText(m_nandemuLblMessage, L""); + m_btnMgr.setText(m_nandfileLblMessage, L""); + m_btnMgr.setText(m_nandemuLblDialog, _t("cfgne11", L"Overall progress:")); + m_btnMgr.setText(m_nandemuLblTitle, _t("cfgne12", L"Nand extractor")); + m_thrdStop = false; + m_thrdProgress = 0.f; + m_thrdWorking = true; + LWP_CreateThread(&thread, (void *(*)(void *))CMenu::_NandDumper, (void *)this, 0, 32768, 40); + } + if(BTN_A_PRESSED && (m_btnMgr.selected(m_nandemuBtnDisable))) + { + _hideNandEmu(); + return 0; + } + + if(m_thrdMessageAdded) + { + LockMutex lock(m_mutex); + m_thrdMessageAdded = false; + if (!m_thrdMessage.empty()) + m_btnMgr.setText(m_nandfileLblDialog, m_thrdMessage); + m_btnMgr.setProgress(m_nandfilePBar, m_fileProgress); + m_btnMgr.setProgress(m_nandemuPBar, m_thrdProgress); + m_btnMgr.setText(m_nandfileLblMessage, wfmt(_fmt("fileprogress", L"%d / %dkb"), m_fileprog/0x400, m_filesize/0x400)); + m_btnMgr.setText(m_nandemuLblMessage, wfmt(_fmt("dumpprogress", L"%i%%"), (int)(m_thrdProgress*100.f))); + + if (!m_thrdWorking) + { + m_btnMgr.setText(m_nandfinLblDialog, wfmt(_fmt("cfgne15", L"Extracted: %d files / %d folders"), m_filesdone, m_foldersdone)); + if(m_dumpsize/0x400 > 0x270f) + m_btnMgr.setText(m_nandemuLblDialog, wfmt(_fmt("cfgne16", L"Total size: %uMb (%d blocks)"), (m_dumpsize/0x100000), (m_dumpsize/0x8000)>>2)); + else + m_btnMgr.setText(m_nandemuLblDialog, wfmt(_fmt("cfgne17", L"Total size: %ukb (%d blocks)"), (m_dumpsize/0x400), (m_dumpsize/0x8000)>>2)); + + _hideNandEmu(); + return 1; + } + } + } + _hideNandEmu(); + return 0; +} + +int CMenu::_NandDumper(void *obj) +{ + CMenu &m = *(CMenu *)obj; + string emuPath; + int emuPartition = -1; + bool emuPartIsValid = false; + m.m_nandext = false; + m.m_sgdump = false; + m.m_dumpsize = 0; + m.m_filesdone = 0; + m.m_foldersdone = 0; + + Nand::Instance()->ResetCounters(); + + if(m.m_current_view == COVERFLOW_CHANNEL) + { + emuPartition = m.m_cfg.getInt("NAND", "partition", 0); + emuPath = m.m_cfg.getString("NAND", "path", ""); + } + else if(m.m_current_view == COVERFLOW_USB) + { + emuPartition = m.m_cfg.getInt("GAMES", "savepartition", -1); + if(emuPartition == -1) + emuPartition = m.m_cfg.getInt("NAND", "partition", 0); + emuPath = m.m_cfg.getString("GAMES", "savepath", m.m_cfg.getString("NAND", "path", "")); + } + + for(u8 i = emuPartition; i <= USB8; ++i) + { + if(!DeviceHandler::Instance()->IsInserted(emuPartition) || DeviceHandler::Instance()->GetFSType(emuPartition) != PART_FS_FAT) + { + emuPartition++; + continue; + } + else + { + emuPartIsValid = true; + if(m.m_current_view == COVERFLOW_CHANNEL) + m.m_cfg.setInt("NAND", "partition", emuPartition); + else if(m.m_current_view == COVERFLOW_USB) + m.m_cfg.setInt("GAMES", "savepartition", emuPartition); + break; + } + } + + if(!emuPartIsValid) + { + m.error(sfmt("No valid FAT partition found for nandemulation!")); + m.m_thrdWorking = false; + m.m_btnMgr.hide(m.m_nandfilePBar); + m.m_btnMgr.hide(m.m_nandfileLblMessage); + LWP_MutexLock(m.m_mutex); + m._setDumpMsg(m._t("cfgne20", L"Extraction failed!"), 1.f, 1.f); + LWP_MutexUnlock(m.m_mutex); + m._hideNandEmu(); + return 0; + } + + if(emuPath.size() == 0) + { + Nand::Instance()->CreatePath("%s:/wiiflow", DeviceName[emuPartition]); + Nand::Instance()->CreatePath("%s:/wiiflow/nandemu", DeviceName[emuPartition]); + if(m.m_current_view == COVERFLOW_CHANNEL) + { + m.m_cfg.setString("NAND", "path", STDEMU_DIR); + emuPath = m.m_cfg.getString("NAND", "path", STDEMU_DIR); + + } + else if(m.m_current_view == COVERFLOW_USB) + { + m.m_cfg.setString("GAMES", "savepath", STDEMU_DIR); + emuPath = m.m_cfg.getString("GAMES", "savepath", STDEMU_DIR); + } + } + m.m_cfg.save(); + + char basepath[64]; + snprintf(basepath, 64, "%s:%s", DeviceName[emuPartition], emuPath.c_str()); + + LWP_MutexLock(m.m_mutex); + m._setDumpMsg(L"Calculating space needed for extraction...", 0.f, 0.f); + LWP_MutexUnlock(m.m_mutex); + + if(m.m_fulldump) + { + m.m_dumpsize = Nand::Instance()->CalcDumpSpace("/", true, CMenu::_ShowProgress, obj); + m.m_nandext = true; + Nand::Instance()->DoNandDump("/", basepath, true, CMenu::_ShowProgress, obj); + } + else + { + bool missingOnly = !m.m_saveall; + string path, npath; + safe_vector saveList; + m.m_sgdump = true; + + if(m.m_saveExtGameId.empty()) + { + m.m_nandexentry = 0; + saveList.reserve(m.m_gameList.size()); + for(u32 i = 0; i < m.m_gameList.size() && !m.m_thrdStop; ++i) + { + LWP_MutexLock(m.m_mutex); + m._setDumpMsg(m._t("cfgne18", L"Listing game saves to extract..."), 0.f, 0.f); + LWP_MutexUnlock(m.m_mutex); + + string id((const char *)m.m_gameList[i].hdr.id, 4); + + int savePath = id.c_str()[0] << 24 | id.c_str()[1] << 16 | id.c_str()[2] << 8 | id.c_str()[3]; + + path = sfmt("%s/title/00010000/%x", basepath, savePath); + npath = sfmt("/title/00010000/%x", savePath); + + if(!missingOnly || !_saveExcists(path.c_str())) + { + if(_nandSaveExcists(npath.c_str())) + { + m.m_nandexentry++; + saveList.push_back(id); + } + } + + } + } + else + saveList.push_back(m.m_saveExtGameId); + + + for(u32 i = 0; i < saveList.size() && !m.m_thrdStop; ++i) + { + char source[ISFS_MAXPATH]; + int savePath = saveList[i].c_str()[0] << 24 | saveList[i].c_str()[1] << 16 | saveList[i].c_str()[2] << 8 | saveList[i].c_str()[3]; + snprintf(source, sizeof(source), "/title/00010000/%x", savePath); + m.m_dumpsize = Nand::Instance()->CalcDumpSpace(source, false, CMenu::_ShowProgress, obj); + } + for(u32 i = 0; i < saveList.size() && !m.m_thrdStop; ++i) + { + char source[ISFS_MAXPATH]; + int savePath = saveList[i].c_str()[0] << 24 | saveList[i].c_str()[1] << 16 | saveList[i].c_str()[2] << 8 | saveList[i].c_str()[3]; + snprintf(source, sizeof(source), "/title/00010000/%x", savePath); + m.m_nandext = true; + Nand::Instance()->DoNandDump(source, basepath, false, CMenu::_ShowProgress, obj); + } + } + + m.m_thrdWorking = false; + LWP_MutexLock(m.m_mutex); + m.m_btnMgr.hide(m.m_nandfilePBar); + m.m_btnMgr.hide(m.m_nandfileLblMessage); + m._setDumpMsg(m._t("cfgne19", L"Extraction finished!"), 1.f, 1.f); + LWP_MutexUnlock(m.m_mutex); + return 0; +} + +void CMenu::_initNandEmuMenu(CMenu::SThemeData &theme) +{ + _addUserLabels(theme, m_nandemuLblUser, ARRAY_SIZE(m_nandemuLblUser), "NANDEMU"); + m_nandemuBg = _texture(theme.texSet, "NANDEMU/BG", "texture", theme.bg); + m_nandemuLblTitle = _addTitle(theme, "NANDEMU/TITLE", theme.titleFont, L"", 20, 30, 600, 60, theme.titleFontColor, FTGX_JUSTIFY_CENTER | FTGX_ALIGN_MIDDLE); + m_nandfileLblMessage = _addLabel(theme, "NANDEMU/FMESSAGE", theme.lblFont, L"", 40, 230, 560, 100, theme.lblFontColor, FTGX_JUSTIFY_CENTER | FTGX_ALIGN_TOP); + m_nandemuLblMessage = _addLabel(theme, "NANDEMU/MESSAGE", theme.lblFont, L"", 40, 350, 560, 100, theme.lblFontColor, FTGX_JUSTIFY_CENTER | FTGX_ALIGN_TOP); + m_nandfileLblDialog = _addLabel(theme, "NANDEMU/FDIALOG", theme.lblFont, L"", 40, 60, 560, 200, theme.lblFontColor, FTGX_JUSTIFY_LEFT | FTGX_ALIGN_MIDDLE); + m_nandfinLblDialog = _addLabel(theme, "NANDEMU/FINDIALOG", theme.lblFont, L"", 40, 120, 560, 200, theme.lblFontColor, FTGX_JUSTIFY_LEFT | FTGX_ALIGN_MIDDLE); + m_nandemuLblDialog = _addLabel(theme, "NANDEMU/DIALOG", theme.lblFont, L"", 40, 180, 560, 200, theme.lblFontColor, FTGX_JUSTIFY_LEFT | FTGX_ALIGN_MIDDLE); + m_nandfilePBar = _addProgressBar(theme, "NANDEMU/FILEPROGRESS_BAR", 40, 200, 560, 20); + m_nandemuPBar = _addProgressBar(theme, "NANDEMU/PROGRESS_BAR", 40, 320, 560, 20); + m_nandemuLblEmulation = _addLabel(theme, "NANDEMU/EMU_SAVE", theme.lblFont, L"", 40, 130, 340, 56, theme.lblFontColor, FTGX_JUSTIFY_LEFT | FTGX_ALIGN_MIDDLE); + m_nandemuLblEmulationVal = _addLabel(theme, "NANDEMU/EMU_SAVE_BTN_GLOBAL", theme.btnFont, L"", 400, 130, 144, 56, theme.btnFontColor, FTGX_JUSTIFY_CENTER | FTGX_ALIGN_MIDDLE, theme.btnTexC); + m_nandemuBtnEmulationM = _addPicButton(theme, "NANDEMU/EMU_SAVE_MINUS", theme.btnTexMinus, theme.btnTexMinusS, 344, 130, 56, 56); + m_nandemuBtnEmulationP = _addPicButton(theme, "NANDEMU/EMU_SAVE_PLUS", theme.btnTexPlus, theme.btnTexPlusS, 544, 130, 56, 56); + m_nandemuLblSaveDump = _addLabel(theme, "NANDEMU/SAVE_DUMP", theme.lblFont, L"", 40, 190, 340, 56, theme.lblFontColor, FTGX_JUSTIFY_LEFT | FTGX_ALIGN_MIDDLE); + m_nandemuBtnAll = _addButton(theme, "NANDEMU/ALL_BTN", theme.btnFont, L"", 350, 190, 250, 56, theme.btnFontColor); + m_nandemuBtnMissing = _addButton(theme, "NANDEMU/MISSING_BTN", theme.btnFont, L"", 350, 250, 250, 56, theme.btnFontColor); + m_nandemuLblNandDump = _addLabel(theme, "NANDEMU/NAND_DUMP", theme.lblFont, L"", 40, 310, 340, 56, theme.lblFontColor, FTGX_JUSTIFY_LEFT | FTGX_ALIGN_MIDDLE); + m_nandemuBtnNandDump = _addButton(theme, "NANDEMU/NAND_DUMP_BTN", theme.btnFont, L"", 350, 310, 250, 56, theme.btnFontColor); + m_nandemuBtnBack = _addButton(theme, "NANDEMU/BACK_BTN", theme.btnFont, L"", 420, 400, 200, 56, theme.btnFontColor); + m_nandemuBtnExtract = _addButton(theme, "NANDEMU/EXTRACT", theme.titleFont, L"", 72, 180, 496, 56, theme.titleFontColor); + m_nandemuBtnDisable = _addButton(theme, "NANDEMU/DISABLE", theme.titleFont, L"", 72, 290, 496, 56, theme.titleFontColor); + m_nandemuLblInit = _addLabel(theme, "NANDEMU/INIT", theme.lblFont, L"", 40, 40, 560, 140, theme.lblFontColor, FTGX_JUSTIFY_LEFT | FTGX_ALIGN_MIDDLE); + + + _setHideAnim(m_nandemuLblTitle, "NANDEMU/TITLE", 0, 0, -2.f, 0.f); + _setHideAnim(m_nandfileLblMessage, "NANDEMU/FMESSAGE", 0, 0, -2.f, 0.f); + _setHideAnim(m_nandemuLblMessage, "NANDEMU/MESSAGE", 0, 0, -2.f, 0.f); + _setHideAnim(m_nandfileLblDialog, "NANDEMU/FDIALOG", 0, 0, -2.f, 0.f); + _setHideAnim(m_nandfinLblDialog, "NANDEMU/FINDIALOG", 0, 0, -2.f, 0.f); + _setHideAnim(m_nandemuLblDialog, "NANDEMU/DIALOG", 0, 0, -2.f, 0.f); + _setHideAnim(m_nandfilePBar, "NANDEMU/FILEPROGRESS_BAR", 0, 0, -2.f, 0.f); + _setHideAnim(m_nandemuPBar, "NANDEMU/PROGRESS_BAR", 0, 0, -2.f, 0.f); + _setHideAnim(m_nandemuLblEmulation, "NANDEMU/EMU_SAVE", 100, 0, -2.f, 0.f); + _setHideAnim(m_nandemuLblEmulationVal, "NANDEMU/EMU_SAVE_BTN_GLOBAL", 0, 0, 1.f, -1.f); + _setHideAnim(m_nandemuBtnEmulationM, "NANDEMU/EMU_SAVE_MINUS", 0, 0, 1.f, -1.f); + _setHideAnim(m_nandemuBtnEmulationP, "NANDEMU/EMU_SAVE_PLUS", 0, 0, 1.f, -1.f); + _setHideAnim(m_nandemuLblSaveDump, "NANDEMU/SAVE_DUMP", 100, 0, -2.f, 0.f); + _setHideAnim(m_nandemuBtnAll, "NANDEMU/ALL_BTN", 0, 0, -2.f, 0.f); + _setHideAnim(m_nandemuBtnMissing, "NANDEMU/MISSING_BTN", 0, 0, -2.f, 0.f); + _setHideAnim(m_nandemuLblNandDump, "NANDEMU/NAND_DUMP", 100, 0, -2.f, 0.f); + _setHideAnim(m_nandemuBtnNandDump, "NANDEMU/NAND_DUMP_BTN", 0, 0, -2.f, 0.f); + _setHideAnim(m_nandemuBtnBack, "NANDEMU/BACK_BTN", 0, 0, -2.f, 0.f); + _setHideAnim(m_nandemuBtnExtract, "NANDEMU/EXTRACT", 0, 0, -2.f, 0.f); + _setHideAnim(m_nandemuBtnDisable, "NANDEMU/DISABLE", 0, 0, -2.f, 0.f); + _setHideAnim(m_nandemuLblInit, "NANDEMU/INIT", 100, 0, -2.f, 0.f); + + _hideNandEmu(true); + _textNandEmu(); +} + +void CMenu::_textNandEmu(void) +{ + m_btnMgr.setText(m_nandemuLblEmulation, _t("cfgne1", L"Nand emulation")); + m_btnMgr.setText(m_nandemuLblSaveDump, _t("cfgne2", L"Extract game saves")); + m_btnMgr.setText(m_nandemuBtnAll, _t("cfgne3", L"All")); + m_btnMgr.setText(m_nandemuBtnMissing, _t("cfgne4", L"Missing")); + m_btnMgr.setText(m_nandemuLblNandDump, _t("cfgne5", L"Extract nand")); + m_btnMgr.setText(m_nandemuBtnNandDump, _t("cfgne6", L"Start")); + m_btnMgr.setText(m_nandemuBtnBack, _t("cfgne7", L"Back")); +} \ No newline at end of file diff --git a/source/music/WavDecoder.cpp b/source/music/WavDecoder.cpp index f086580d..8a5c585b 100644 --- a/source/music/WavDecoder.cpp +++ b/source/music/WavDecoder.cpp @@ -87,17 +87,17 @@ void WavDecoder::OpenFile() SWaveChunk DataChunk; file_fd->read((u8 *) &DataChunk, sizeof(SWaveChunk)); - if(DataChunk.magicDATA == 'fact') - { - DataOffset += 8+le32(DataChunk.size); - file_fd->seek(DataOffset, SEEK_SET); - file_fd->read((u8 *) &DataChunk, sizeof(SWaveChunk)); - } - if(DataChunk.magicDATA != 'data') - { - CloseFile(); - return; - } + while(DataChunk.magicDATA != 'data') + { + DataOffset += 8+le32(DataChunk.size); + file_fd->seek(DataOffset, SEEK_SET); + int ret = file_fd->read((u8 *) &DataChunk, sizeof(SWaveChunk)); + if(ret <= 0) + { + CloseFile(); + return; + } + } DataOffset += 8; DataSize = le32(DataChunk.size);