From 477c21e946afa7f8057dac5728194e316948f3a1 Mon Sep 17 00:00:00 2001 From: LPFaint99 Date: Sun, 18 Aug 2013 14:58:23 -0700 Subject: [PATCH 1/2] fix import/export of games with folders. remove copy protection bit from banner - should allow *some* copy protected games to be moved to a real system; ex: super smash bros brawl, mario kart games with a nocopy/nomove folder cannot be imported to a real system without using homebrew tools, warn for these saves ex: guitar hero remove some unneccessary class fields the class is still incredibly ugly :( --- Source/Core/DolphinWX/Src/FrameTools.cpp | 4 +- Source/Core/DolphinWX/Src/GameListCtrl.cpp | 3 +- .../Src/MemoryCards/WiiSaveCrypted.cpp | 178 ++++++++++-------- .../Src/MemoryCards/WiiSaveCrypted.h | 25 ++- 4 files changed, 112 insertions(+), 98 deletions(-) diff --git a/Source/Core/DolphinWX/Src/FrameTools.cpp b/Source/Core/DolphinWX/Src/FrameTools.cpp index dcca6ccf66..40bc29a1ec 100644 --- a/Source/Core/DolphinWX/Src/FrameTools.cpp +++ b/Source/Core/DolphinWX/Src/FrameTools.cpp @@ -1320,9 +1320,7 @@ void CFrame::OnImportSave(wxCommandEvent& WXUNUSED (event)) if (!path.IsEmpty()) { - // TODO: Does this actually need to be dynamically allocated for some reason? - CWiiSaveCrypted* saveFile = new CWiiSaveCrypted(WxStrToStr(path).c_str()); - delete saveFile; + CWiiSaveCrypted::ImportWiiSave(WxStrToStr(path).c_str()); } } diff --git a/Source/Core/DolphinWX/Src/GameListCtrl.cpp b/Source/Core/DolphinWX/Src/GameListCtrl.cpp index c8e2e94072..a0186fa7e0 100644 --- a/Source/Core/DolphinWX/Src/GameListCtrl.cpp +++ b/Source/Core/DolphinWX/Src/GameListCtrl.cpp @@ -969,8 +969,7 @@ void CGameListCtrl::OnExportSave(wxCommandEvent& WXUNUSED (event)) if (Iso->GetTitleID((u8*)&title)) { title = Common::swap64(title); - CWiiSaveCrypted* exportSave = new CWiiSaveCrypted("", title); - delete exportSave; + CWiiSaveCrypted::ExportWiiSave(title); } delete Iso; } diff --git a/Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.cpp b/Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.cpp index cfdccf26c2..641805fc1b 100644 --- a/Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.cpp +++ b/Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.cpp @@ -21,18 +21,28 @@ const u8 MD5_BLANKER[0x10] = {0x0E, 0x65, 0x37, 0x81, 0x99, 0xBE, 0x45, 0x17, 0xAB, 0x06, 0xEC, 0x22, 0x45, 0x1A, 0x57, 0x93}; const u32 NG_id = 0x0403AC68; +bool CWiiSaveCrypted::ImportWiiSave(const char* FileName) +{ + CWiiSaveCrypted saveFile(FileName); + return saveFile.b_valid; +} + +bool CWiiSaveCrypted::ExportWiiSave(u64 TitleID) +{ + CWiiSaveCrypted exportSave("", TitleID); + return exportSave.b_valid; +} + CWiiSaveCrypted::CWiiSaveCrypted(const char* FileName, u64 TitleID) : m_TitleID(TitleID) { Common::ReadReplacements(replacements); - strcpy(pathData_bin, FileName); + encryptedSavePath = std::string(FileName); memcpy(SD_IV, "\x21\x67\x12\xE6\xAA\x1F\x68\x9F\x95\xC5\xA2\x23\x24\xDC\x6A\x98", 0x10); if (!TitleID) // Import { AES_set_decrypt_key(SDKey, 128, &m_AES_KEY); - do - { b_valid = true; ReadHDR(); ReadBKHDR(); @@ -41,13 +51,11 @@ CWiiSaveCrypted::CWiiSaveCrypted(const char* FileName, u64 TitleID) if (b_valid) { SuccessAlertT("Successfully imported save files"); - b_tryAgain = false; } else { - b_tryAgain = AskYesNoT("Import failed, try again?"); + PanicAlertT("Import failed"); } - } while(b_tryAgain); } else { @@ -55,33 +63,29 @@ CWiiSaveCrypted::CWiiSaveCrypted(const char* FileName, u64 TitleID) if (getPaths(true)) { - do + b_valid = true; + WriteHDR(); + WriteBKHDR(); + ExportWiiSaveFiles(); + do_sig(); + if (b_valid) { - b_valid = true; - WriteHDR(); - WriteBKHDR(); - ExportWiiSaveFiles(); - do_sig(); - if (b_valid) - { - SuccessAlertT("Successfully exported file to %s", pathData_bin); - b_tryAgain = false; - } - else - { - b_tryAgain = AskYesNoT("Export failed, try again?"); - } - } while(b_tryAgain); + SuccessAlertT("Successfully exported file to %s", encryptedSavePath.c_str()); + } + else + { + PanicAlertT("Export failed"); + } } } } void CWiiSaveCrypted::ReadHDR() { - File::IOFile fpData_bin(pathData_bin, "rb"); + File::IOFile fpData_bin(encryptedSavePath, "rb"); if (!fpData_bin) { - PanicAlertT("Cannot open %s", pathData_bin); + PanicAlertT("Cannot open %s", encryptedSavePath.c_str()); b_valid = false; return; } @@ -94,16 +98,19 @@ void CWiiSaveCrypted::ReadHDR() fpData_bin.Close(); AES_cbc_encrypt((const u8*)&_encryptedHeader, (u8*)&_header, HEADER_SZ, &m_AES_KEY, SD_IV, AES_DECRYPT); - _bannerSize = Common::swap32(_header.hdr.BannerSize); - if ((_bannerSize < FULL_BNR_MIN) || (_bannerSize > FULL_BNR_MAX) || - (((_bannerSize - BNR_SZ) % ICON_SZ) != 0)) + u32 bannerSize = Common::swap32(_header.hdr.BannerSize); + if ((bannerSize < FULL_BNR_MIN) || (bannerSize > FULL_BNR_MAX) || + (((bannerSize - BNR_SZ) % ICON_SZ) != 0)) { - PanicAlertT("Not a Wii save or read failure for file header size %x", _bannerSize); + PanicAlertT("Not a Wii save or read failure for file header size %x", bannerSize); b_valid = false; return; } m_TitleID = Common::swap64(_header.hdr.SaveGameTitle); + + u8 md5_file[16], + md5_calc[16]; memcpy(md5_file, _header.hdr.Md5, 0x10); memcpy(_header.hdr.Md5, MD5_BLANKER, 0x10); md5((u8*)&_header, HEADER_SZ, md5_calc); @@ -118,11 +125,12 @@ void CWiiSaveCrypted::ReadHDR() b_valid = false; return; } + std::string BannerFilePath = WiiTitlePath + "banner.bin"; if (!File::Exists(BannerFilePath) || AskYesNoT("%s already exists, overwrite?", BannerFilePath.c_str())) { INFO_LOG(CONSOLE, "Creating file %s", BannerFilePath.c_str()); File::IOFile fpBanner_bin(BannerFilePath, "wb"); - fpBanner_bin.WriteBytes(_header.BNR, _bannerSize); + fpBanner_bin.WriteBytes(_header.BNR, bannerSize); } } @@ -131,12 +139,13 @@ void CWiiSaveCrypted::WriteHDR() if (!b_valid) return; memset(&_header, 0, HEADER_SZ); + std::string BannerFilePath = WiiTitlePath + "banner.bin"; u32 bannerSize = File::GetSize(BannerFilePath); _header.hdr.BannerSize = Common::swap32(bannerSize); _header.hdr.SaveGameTitle = Common::swap64(m_TitleID); memcpy(_header.hdr.Md5, MD5_BLANKER, 0x10); - _header.hdr.Permissions = 0x35; + _header.hdr.Permissions = 0x3C; File::IOFile fpBanner_bin(BannerFilePath, "rb"); if (!fpBanner_bin.ReadBytes(_header.BNR, bannerSize)) @@ -145,16 +154,19 @@ void CWiiSaveCrypted::WriteHDR() b_valid = false; return; } - + // remove nocopy flag + _header.BNR[7] &= ~1; + + u8 md5_calc[16]; md5((u8*)&_header, HEADER_SZ, md5_calc); memcpy(_header.hdr.Md5, md5_calc, 0x10); AES_cbc_encrypt((const unsigned char *)&_header, (u8*)&_encryptedHeader, HEADER_SZ, &m_AES_KEY, SD_IV, AES_ENCRYPT); - File::IOFile fpData_bin(pathData_bin, "wb"); + File::IOFile fpData_bin(encryptedSavePath, "wb"); if (!fpData_bin.WriteBytes(&_encryptedHeader, HEADER_SZ)) { - PanicAlertT("Failed to write header for %s", pathData_bin); + PanicAlertT("Failed to write header for %s", encryptedSavePath.c_str()); b_valid = false; } } @@ -165,10 +177,10 @@ void CWiiSaveCrypted::ReadBKHDR() { if (!b_valid) return; - File::IOFile fpData_bin(pathData_bin, "rb"); + File::IOFile fpData_bin(encryptedSavePath, "rb"); if (!fpData_bin) { - PanicAlertT("Cannot open %s", pathData_bin); + PanicAlertT("Cannot open %s", encryptedSavePath.c_str()); b_valid = false; return; } @@ -215,7 +227,7 @@ void CWiiSaveCrypted::WriteBKHDR() bkhdr.totalSize = Common::swap32(_sizeOfFiles + FULL_CERT_SZ); bkhdr.SaveGameTitle = Common::swap64(m_TitleID); - File::IOFile fpData_bin(pathData_bin, "ab"); + File::IOFile fpData_bin(encryptedSavePath, "ab"); if (!fpData_bin.WriteBytes(&bkhdr, BK_SZ)) { PanicAlertT("Failed to write bkhdr"); @@ -227,10 +239,10 @@ void CWiiSaveCrypted::ImportWiiSaveFiles() { if (!b_valid) return; - File::IOFile fpData_bin(pathData_bin, "rb"); + File::IOFile fpData_bin(encryptedSavePath, "rb"); if (!fpData_bin) { - PanicAlertT("Cannot open %s", pathData_bin); + PanicAlertT("Cannot open %s", encryptedSavePath.c_str()); b_valid = false; return; } @@ -244,11 +256,11 @@ void CWiiSaveCrypted::ImportWiiSaveFiles() { memset(&_tmpFileHDR, 0, FILE_HDR_SZ); memset(IV, 0, 0x10); - _fileSize = 0; + u32 _fileSize = 0; if (!fpData_bin.ReadBytes(&_tmpFileHDR, FILE_HDR_SZ)) { - PanicAlertT("Failed to write header for file %d", i); + PanicAlertT("Failed to read header for file %d", i); b_valid = false; } @@ -267,14 +279,15 @@ void CWiiSaveCrypted::ImportWiiSaveFiles() } std::string fullFilePath = WiiTitlePath + fileName; - File::CreateFullPath(fullFilePath); + File::CreateFullPath(fullFilePath); if (_tmpFileHDR.type == 1) { _fileSize = Common::swap32(_tmpFileHDR.size); u32 RoundedFileSize = ROUND_UP(_fileSize, BLOCK_SZ); - _encryptedData = new u8[RoundedFileSize]; - _data = new u8[RoundedFileSize]; - if (!fpData_bin.ReadBytes(_encryptedData, RoundedFileSize)) + std::vector _data,_encryptedData; + _data.reserve(RoundedFileSize); + _encryptedData.reserve(RoundedFileSize); + if (!fpData_bin.ReadBytes(&_encryptedData[0], RoundedFileSize)) { PanicAlertT("Failed to read data from file %d", i); b_valid = false; @@ -283,17 +296,15 @@ void CWiiSaveCrypted::ImportWiiSaveFiles() memcpy(IV, _tmpFileHDR.IV, 0x10); - AES_cbc_encrypt((const unsigned char *)_encryptedData, _data, RoundedFileSize, &m_AES_KEY, IV, AES_DECRYPT); - delete []_encryptedData; + AES_cbc_encrypt((const unsigned char *)&_encryptedData[0], &_data[0], RoundedFileSize, &m_AES_KEY, IV, AES_DECRYPT); if (!File::Exists(fullFilePath) || AskYesNoT("%s already exists, overwrite?", fullFilePath.c_str())) { INFO_LOG(CONSOLE, "Creating file %s", fullFilePath.c_str()); File::IOFile fpRawSaveFile(fullFilePath, "wb"); - fpRawSaveFile.WriteBytes(_data, _fileSize); + fpRawSaveFile.WriteBytes(&_data[0], _fileSize); } - delete []_data; } } } @@ -303,25 +314,29 @@ void CWiiSaveCrypted::ExportWiiSaveFiles() { if (!b_valid) return; - u8 *__ENCdata, - *__data; - for(u32 i = 0; i < _numberOfFiles; i++) { FileHDR tmpFileHDR; std::string __name, __ext; memset(&tmpFileHDR, 0, FILE_HDR_SZ); - - _fileSize = File::GetSize(FilesList[i]); - _roundedfileSize = ROUND_UP(_fileSize, BLOCK_SZ); - + + u32 _fileSize = 0; + if (File::IsDirectory(FilesList[i])) + { + tmpFileHDR.type = 2; + } + else + { + _fileSize = File::GetSize(FilesList[i]); + tmpFileHDR.type = 1; + } + + u32 _roundedfileSize = ROUND_UP(_fileSize, BLOCK_SZ); tmpFileHDR.magic = Common::swap32(FILE_HDR_MAGIC); tmpFileHDR.size = Common::swap32(_fileSize); - tmpFileHDR.Permissions = 0x35; - tmpFileHDR.type = File::IsDirectory(FilesList[i]) ? 2 : 1; + tmpFileHDR.Permissions = 0x3c; - SplitPath(FilesList[i], NULL, &__name, &__ext); - __name += __ext; + __name = FilesList[i].substr(WiiTitlePath.length()+1); for (Common::replace_v::const_iterator iter = replacements.begin(); iter != replacements.end(); ++iter) @@ -341,7 +356,7 @@ void CWiiSaveCrypted::ExportWiiSaveFiles() strncpy((char *)tmpFileHDR.name, __name.c_str(), __name.length()); { - File::IOFile fpData_bin(pathData_bin, "ab"); + File::IOFile fpData_bin(encryptedSavePath, "ab"); fpData_bin.WriteBytes(&tmpFileHDR, FILE_HDR_SZ); } @@ -359,22 +374,23 @@ void CWiiSaveCrypted::ExportWiiSaveFiles() PanicAlertT("%s failed to open", FilesList[i].c_str()); b_valid = false; } - __data = new u8[_roundedfileSize]; - __ENCdata = new u8[_roundedfileSize]; - memset(__data, 0, _roundedfileSize); - if (!fpRawSaveFile.ReadBytes(__data, _fileSize)) + + std::vector _data,_encryptedData; + _data.reserve(_roundedfileSize); + _encryptedData.reserve(_roundedfileSize); + memset(&_data[0], 0, _roundedfileSize); + if (!fpRawSaveFile.ReadBytes(&_data[0], _fileSize)) { PanicAlertT("Failed to read data from file: %s", FilesList[i].c_str()); b_valid = false; } - AES_cbc_encrypt((const u8*)__data, __ENCdata, _roundedfileSize, &m_AES_KEY, tmpFileHDR.IV, AES_ENCRYPT); + AES_cbc_encrypt((const u8*)&_data[0], &_encryptedData[0], _roundedfileSize, &m_AES_KEY, tmpFileHDR.IV, AES_ENCRYPT); - File::IOFile fpData_bin(pathData_bin, "ab"); - fpData_bin.WriteBytes(__ENCdata, _roundedfileSize); + File::IOFile fpData_bin(encryptedSavePath, "ab"); + if (!fpData_bin.WriteBytes(&_encryptedData[0], _roundedfileSize)) + PanicAlertT("Failed to write data to file: %s", encryptedSavePath.c_str()); - delete [] __data; - delete [] __ENCdata; } } @@ -424,7 +440,7 @@ void CWiiSaveCrypted::do_sig() data_size = Common::swap32(bkhdr.sizeOfFiles) + 0x80; - File::IOFile fpData_bin(pathData_bin, "rb"); + File::IOFile fpData_bin(encryptedSavePath, "rb"); if (!fpData_bin) { b_valid = false; @@ -443,7 +459,7 @@ void CWiiSaveCrypted::do_sig() sha1(hash, 20, hash); delete []data; - fpData_bin.Open(pathData_bin, "ab"); + fpData_bin.Open(encryptedSavePath, "ab"); if (!fpData_bin) { b_valid = false; @@ -478,7 +494,6 @@ bool CWiiSaveCrypted::getPaths(bool forExport) if (m_TitleID) { WiiTitlePath = Common::GetTitleDataPath(m_TitleID); - BannerFilePath = WiiTitlePath + "banner.bin"; } if (forExport) @@ -495,16 +510,16 @@ bool CWiiSaveCrypted::getPaths(bool forExport) return false; } - if(!File::Exists(BannerFilePath)) + if(!File::Exists(WiiTitlePath + "banner.bin")) { b_valid = false; PanicAlertT("No banner file found for title %s", GameID); return false; } - if (strlen(pathData_bin) == 0) - strcpy(pathData_bin, "."); // If no path was passed, use current dir - sprintf(pathData_bin, "%s/private/wii/title/%s/data.bin", pathData_bin, GameID); - File::CreateFullPath(pathData_bin); + if (encryptedSavePath.length() == 0) + encryptedSavePath = "."; // If no path was passed, use current dir + encryptedSavePath += StringFromFormat("/private/wii/title/%s/data.bin", GameID); + File::CreateFullPath(encryptedSavePath); } else { @@ -535,15 +550,20 @@ void CWiiSaveCrypted::ScanForFiles(std::string savDir, std::vector& if (strncmp(FST_Temp.children.at(j).virtualName.c_str(), "banner.bin", 10) != 0) { (*_numFiles)++; - *_sizeFiles += FILE_HDR_SZ + ROUND_UP(FST_Temp.children.at(j).size, BLOCK_SZ); - + *_sizeFiles += FILE_HDR_SZ; if (FST_Temp.children.at(j).isDirectory) { + if ((FST_Temp.children.at(j).virtualName == "nocopy") || FST_Temp.children.at(j).virtualName == "nomove") + { + PanicAlert("This save will likely require homebrew tools to copy to a real wii"); + } + Directories.push_back(FST_Temp.children.at(j).physicalName); } else { FileList.push_back(FST_Temp.children.at(j).physicalName); + *_sizeFiles += ROUND_UP(FST_Temp.children.at(j).size, BLOCK_SZ); } } } diff --git a/Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.h b/Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.h index c27ee58a19..e4fd67134d 100644 --- a/Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.h +++ b/Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.h @@ -16,6 +16,10 @@ class CWiiSaveCrypted { public: + bool static ImportWiiSave(const char* FileName); + bool static ExportWiiSave(u64 TitleID); + +private: CWiiSaveCrypted(const char* FileName, u64 TitleID = 0); ~CWiiSaveCrypted(); void ReadHDR(); @@ -30,33 +34,26 @@ public: bool getPaths(bool forExport = false); void ScanForFiles(std::string savDir, std::vector&FilesList, u32 *_numFiles, u32 *_sizeFiles); -private: + AES_KEY m_AES_KEY; u8 SD_IV[0x10]; std::vector FilesList; - char pathData_bin[2048]; + std::string encryptedSavePath; std::string BannerFilePath, WiiTitlePath; - u8 IV[0x10], - *_encryptedData, - *_data, - md5_file[16], - md5_calc[16]; - - u32 _bannerSize, + u8 IV[0x10]; + + u32 //_bannerSize, _numberOfFiles, _sizeOfFiles, - _totalSize, - _fileSize, - _roundedfileSize; + _totalSize; u64 m_TitleID; - bool b_valid, - b_tryAgain; + bool b_valid; enum { From c2d208df96b4fc839b6f32756b1836e1a127c205 Mon Sep 17 00:00:00 2001 From: LPFaint99 Date: Sun, 18 Aug 2013 14:59:05 -0700 Subject: [PATCH 2/2] add the ability to export all save files --- Source/Core/DolphinWX/Src/Frame.cpp | 1 + Source/Core/DolphinWX/Src/Frame.h | 1 + Source/Core/DolphinWX/Src/FrameTools.cpp | 8 ++++- Source/Core/DolphinWX/Src/Globals.h | 1 + .../Src/MemoryCards/WiiSaveCrypted.cpp | 36 +++++++++++++++++++ .../Src/MemoryCards/WiiSaveCrypted.h | 1 + 6 files changed, 47 insertions(+), 1 deletion(-) diff --git a/Source/Core/DolphinWX/Src/Frame.cpp b/Source/Core/DolphinWX/Src/Frame.cpp index 613cdc35ab..5d0113ef53 100644 --- a/Source/Core/DolphinWX/Src/Frame.cpp +++ b/Source/Core/DolphinWX/Src/Frame.cpp @@ -191,6 +191,7 @@ EVT_MENU(IDM_NETPLAY, CFrame::OnNetPlay) EVT_MENU(IDM_BROWSE, CFrame::OnBrowse) EVT_MENU(IDM_MEMCARD, CFrame::OnMemcard) EVT_MENU(IDM_IMPORTSAVE, CFrame::OnImportSave) +EVT_MENU(IDM_EXPORTALLSAVE, CFrame::OnExportAllSaves) EVT_MENU(IDM_CHEATS, CFrame::OnShow_CheatsWindow) EVT_MENU(IDM_CHANGEDISC, CFrame::OnChangeDisc) EVT_MENU(IDM_MENU_INSTALLWAD, CFrame::OnInstallWAD) diff --git a/Source/Core/DolphinWX/Src/Frame.h b/Source/Core/DolphinWX/Src/Frame.h index 2891d9931c..a904a7aa5f 100644 --- a/Source/Core/DolphinWX/Src/Frame.h +++ b/Source/Core/DolphinWX/Src/Frame.h @@ -324,6 +324,7 @@ private: void OnMemcard(wxCommandEvent& event); // Misc void OnImportSave(wxCommandEvent& event); + void OnExportAllSaves(wxCommandEvent& event); void OnNetPlay(wxCommandEvent& event); diff --git a/Source/Core/DolphinWX/Src/FrameTools.cpp b/Source/Core/DolphinWX/Src/FrameTools.cpp index 40bc29a1ec..6663a59665 100644 --- a/Source/Core/DolphinWX/Src/FrameTools.cpp +++ b/Source/Core/DolphinWX/Src/FrameTools.cpp @@ -190,7 +190,8 @@ void CFrame::CreateMenu() // Tools menu wxMenu* toolsMenu = new wxMenu; toolsMenu->Append(IDM_MEMCARD, _("&Memcard Manager (GC)")); - toolsMenu->Append(IDM_IMPORTSAVE, _("Wii Save Import")); + toolsMenu->Append(IDM_IMPORTSAVE, _("Import Wii Save")); + toolsMenu->Append(IDM_EXPORTALLSAVE, _("Export All Wii Saves")); toolsMenu->Append(IDM_CHEATS, _("&Cheats Manager")); toolsMenu->Append(IDM_NETPLAY, _("Start &NetPlay")); @@ -1310,6 +1311,11 @@ void CFrame::OnMemcard(wxCommandEvent& WXUNUSED (event)) MemcardManager.ShowModal(); } +void CFrame::OnExportAllSaves(wxCommandEvent& WXUNUSED (event)) +{ + CWiiSaveCrypted::ExportAllSaves(); +} + void CFrame::OnImportSave(wxCommandEvent& WXUNUSED (event)) { wxString path = wxFileSelector(_("Select the save file"), diff --git a/Source/Core/DolphinWX/Src/Globals.h b/Source/Core/DolphinWX/Src/Globals.h index 5930427620..f55a6b2b66 100644 --- a/Source/Core/DolphinWX/Src/Globals.h +++ b/Source/Core/DolphinWX/Src/Globals.h @@ -231,6 +231,7 @@ enum IDM_OPENSAVEFOLDER, IDM_EXPORTSAVE, IDM_IMPORTSAVE, + IDM_EXPORTALLSAVE, IDM_SETDEFAULTGCM, IDM_DELETEGCM, IDM_COMPRESSGCM, diff --git a/Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.cpp b/Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.cpp index 641805fc1b..31985f374f 100644 --- a/Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.cpp +++ b/Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.cpp @@ -11,6 +11,7 @@ #include "FileUtil.h" #include "MathUtil.h" #include "NandPaths.h" +#include "FileUtil.h" #include static Common::replace_v replacements; @@ -33,6 +34,41 @@ bool CWiiSaveCrypted::ExportWiiSave(u64 TitleID) return exportSave.b_valid; } +void CWiiSaveCrypted::ExportAllSaves() +{ + std::string titleFolder = File::GetUserPath(D_WIIUSER_IDX) + "title"; + std::vector titles; + u32 pathMask = 0x00010000; + for (int i = 0; i < 8; ++i) + { + File::FSTEntry FST_Temp; + std::string folder = StringFromFormat("%s/%08x/", titleFolder.c_str(), pathMask | i); + File::ScanDirectoryTree(folder, FST_Temp); + + for (u32 j = 0; j < FST_Temp.children.size(); j++) + { + if (FST_Temp.children[j].isDirectory) + { + u32 gameid; + if (AsciiToHex(FST_Temp.children[j].virtualName.c_str(), gameid)) + { + std::string bannerPath = StringFromFormat("%s%08x/data/banner.bin", folder.c_str(), gameid); + if (File::Exists(bannerPath)) + { + u64 titleID = (((u64)pathMask | i) << 32) | gameid; + titles.push_back(titleID); + } + } + } + } + } + SuccessAlertT("Found %llx save files", titles.size()); + for (u32 i = 0; i < titles.size(); ++i) + { + CWiiSaveCrypted* exportSave = new CWiiSaveCrypted("", titles[i]); + delete exportSave; + } +} CWiiSaveCrypted::CWiiSaveCrypted(const char* FileName, u64 TitleID) : m_TitleID(TitleID) { diff --git a/Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.h b/Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.h index e4fd67134d..e3a77b4f72 100644 --- a/Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.h +++ b/Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.h @@ -18,6 +18,7 @@ class CWiiSaveCrypted public: bool static ImportWiiSave(const char* FileName); bool static ExportWiiSave(u64 TitleID); + void static ExportAllSaves(); private: CWiiSaveCrypted(const char* FileName, u64 TitleID = 0);