From 00bc1f28f2f644abac649221c6530501206f91f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sat, 12 May 2018 22:39:14 +0200 Subject: [PATCH 1/9] Rename CWiiSaveCrypted to WiiSave --- Source/Core/Core/CMakeLists.txt | 2 +- Source/Core/Core/Core.vcxproj | 4 +- Source/Core/Core/Core.vcxproj.filters | 6 +-- .../HW/{WiiSaveCrypted.cpp => WiiSave.cpp} | 53 +++++++++---------- .../Core/HW/{WiiSaveCrypted.h => WiiSave.h} | 6 +-- Source/Core/DolphinQt2/GameList/GameList.cpp | 4 +- Source/Core/DolphinQt2/MenuBar.cpp | 6 +-- Source/Core/DolphinWX/FrameTools.cpp | 6 +-- Source/Core/DolphinWX/GameListCtrl.cpp | 4 +- 9 files changed, 45 insertions(+), 46 deletions(-) rename Source/Core/Core/HW/{WiiSaveCrypted.cpp => WiiSave.cpp} (92%) rename Source/Core/Core/HW/{WiiSaveCrypted.h => WiiSave.h} (96%) diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index 26ab98f803..9b1094dd48 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -150,7 +150,7 @@ add_library(core HW/WiimoteEmu/Encryption.cpp HW/WiimoteEmu/Speaker.cpp HW/WiimoteReal/WiimoteReal.cpp - HW/WiiSaveCrypted.cpp + HW/WiiSave.cpp IOS/Device.cpp IOS/DeviceStub.cpp IOS/IOS.cpp diff --git a/Source/Core/Core/Core.vcxproj b/Source/Core/Core/Core.vcxproj index 3a1aeee2ea..ad815d88a4 100644 --- a/Source/Core/Core/Core.vcxproj +++ b/Source/Core/Core/Core.vcxproj @@ -179,7 +179,7 @@ - + @@ -437,7 +437,7 @@ - + diff --git a/Source/Core/Core/Core.vcxproj.filters b/Source/Core/Core/Core.vcxproj.filters index 25a151d371..a16e67b8e1 100644 --- a/Source/Core/Core/Core.vcxproj.filters +++ b/Source/Core/Core/Core.vcxproj.filters @@ -561,7 +561,7 @@ HW %28Flipper/Hollywood%29 - + HW %28Flipper/Hollywood%29 @@ -1242,7 +1242,7 @@ HW %28Flipper/Hollywood%29 - + HW %28Flipper/Hollywood%29 @@ -1578,4 +1578,4 @@ - \ No newline at end of file + diff --git a/Source/Core/Core/HW/WiiSaveCrypted.cpp b/Source/Core/Core/HW/WiiSave.cpp similarity index 92% rename from Source/Core/Core/HW/WiiSaveCrypted.cpp rename to Source/Core/Core/HW/WiiSave.cpp index 28c9150b34..5802c0faa4 100644 --- a/Source/Core/Core/HW/WiiSaveCrypted.cpp +++ b/Source/Core/Core/HW/WiiSave.cpp @@ -7,7 +7,7 @@ // Licensed under the terms of the GNU GPL, version 2 // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt -#include "Core/HW/WiiSaveCrypted.h" +#include "Core/HW/WiiSave.h" #include #include @@ -31,21 +31,21 @@ #include "Common/StringUtil.h" #include "Common/Swap.h" -const u8 CWiiSaveCrypted::s_sd_key[16] = {0xAB, 0x01, 0xB9, 0xD8, 0xE1, 0x62, 0x2B, 0x08, - 0xAF, 0xBA, 0xD8, 0x4D, 0xBF, 0xC2, 0xA5, 0x5D}; -const u8 CWiiSaveCrypted::s_md5_blanker[16] = {0x0E, 0x65, 0x37, 0x81, 0x99, 0xBE, 0x45, 0x17, - 0xAB, 0x06, 0xEC, 0x22, 0x45, 0x1A, 0x57, 0x93}; -const u32 CWiiSaveCrypted::s_ng_id = 0x0403AC68; +const u8 WiiSave::s_sd_key[16] = {0xAB, 0x01, 0xB9, 0xD8, 0xE1, 0x62, 0x2B, 0x08, + 0xAF, 0xBA, 0xD8, 0x4D, 0xBF, 0xC2, 0xA5, 0x5D}; +const u8 WiiSave::s_md5_blanker[16] = {0x0E, 0x65, 0x37, 0x81, 0x99, 0xBE, 0x45, 0x17, + 0xAB, 0x06, 0xEC, 0x22, 0x45, 0x1A, 0x57, 0x93}; +const u32 WiiSave::s_ng_id = 0x0403AC68; -bool CWiiSaveCrypted::ImportWiiSave(const std::string& filename) +bool WiiSave::ImportWiiSave(const std::string& filename) { - CWiiSaveCrypted save_file(filename); + WiiSave save_file(filename); return save_file.m_valid; } -bool CWiiSaveCrypted::ExportWiiSave(u64 title_id) +bool WiiSave::ExportWiiSave(u64 title_id) { - CWiiSaveCrypted export_save("", title_id); + WiiSave export_save("", title_id); if (export_save.m_valid) { SuccessAlertT("Successfully exported file to %s", export_save.m_encrypted_save_path.c_str()); @@ -57,7 +57,7 @@ bool CWiiSaveCrypted::ExportWiiSave(u64 title_id) return export_save.m_valid; } -void CWiiSaveCrypted::ExportAllSaves() +void WiiSave::ExportAllSaves() { std::string title_folder = File::GetUserPath(D_WIIROOT_IDX) + "/title"; std::vector titles; @@ -89,7 +89,7 @@ void CWiiSaveCrypted::ExportAllSaves() u32 success = 0; for (const u64& title : titles) { - CWiiSaveCrypted export_save{"", title}; + WiiSave export_save{"", title}; if (export_save.m_valid) success++; } @@ -97,7 +97,7 @@ void CWiiSaveCrypted::ExportAllSaves() (File::GetUserPath(D_USER_IDX) + "private/wii/title/").c_str()); } -CWiiSaveCrypted::CWiiSaveCrypted(const std::string& filename, u64 title_id) +WiiSave::WiiSave(const std::string& filename, u64 title_id) : m_encrypted_save_path(filename), m_title_id(title_id) { memcpy(m_sd_iv, "\x21\x67\x12\xE6\xAA\x1F\x68\x9F\x95\xC5\xA2\x23\x24\xDC\x6A\x98", 0x10); @@ -134,7 +134,7 @@ CWiiSaveCrypted::CWiiSaveCrypted(const std::string& filename, u64 title_id) } } -void CWiiSaveCrypted::ReadHDR() +void WiiSave::ReadHDR() { File::IOFile data_file(m_encrypted_save_path, "rb"); if (!data_file) @@ -197,7 +197,7 @@ void CWiiSaveCrypted::ReadHDR() } } -void CWiiSaveCrypted::WriteHDR() +void WiiSave::WriteHDR() { if (!m_valid) return; @@ -236,7 +236,7 @@ void CWiiSaveCrypted::WriteHDR() } } -void CWiiSaveCrypted::ReadBKHDR() +void WiiSave::ReadBKHDR() { if (!m_valid) return; @@ -282,7 +282,7 @@ void CWiiSaveCrypted::ReadBKHDR() } } -void CWiiSaveCrypted::WriteBKHDR() +void WiiSave::WriteBKHDR() { if (!m_valid) return; @@ -307,7 +307,7 @@ void CWiiSaveCrypted::WriteBKHDR() } } -void CWiiSaveCrypted::ImportWiiSaveFiles() +void WiiSave::ImportWiiSaveFiles() { if (!m_valid) return; @@ -391,7 +391,7 @@ void CWiiSaveCrypted::ImportWiiSaveFiles() } } -void CWiiSaveCrypted::ExportWiiSaveFiles() +void WiiSave::ExportWiiSaveFiles() { if (!m_valid) return; @@ -471,7 +471,7 @@ void CWiiSaveCrypted::ExportWiiSaveFiles() } } -void CWiiSaveCrypted::do_sig() +void WiiSave::do_sig() { if (!m_valid) return; @@ -550,8 +550,8 @@ void CWiiSaveCrypted::do_sig() m_valid = data_file.IsGood(); } -void CWiiSaveCrypted::make_ec_cert(u8* cert, const u8* sig, const char* signer, const char* name, - const u8* priv, const u32 key_id) +void WiiSave::make_ec_cert(u8* cert, const u8* sig, const char* signer, const char* name, + const u8* priv, const u32 key_id) { memset(cert, 0, 0x180); *(u32*)cert = Common::swap32(0x10002); @@ -564,7 +564,7 @@ void CWiiSaveCrypted::make_ec_cert(u8* cert, const u8* sig, const char* signer, ec_priv_to_pub(priv, cert + 0x108); } -bool CWiiSaveCrypted::getPaths(bool for_export) +bool WiiSave::getPaths(bool for_export) { if (m_title_id) { @@ -606,9 +606,8 @@ bool CWiiSaveCrypted::getPaths(bool for_export) return true; } -void CWiiSaveCrypted::ScanForFiles(const std::string& save_directory, - std::vector& file_list, u32* num_files, - u32* size_files) +void WiiSave::ScanForFiles(const std::string& save_directory, std::vector& file_list, + u32* num_files, u32* size_files) { std::vector directories; directories.push_back(save_directory); @@ -653,6 +652,6 @@ void CWiiSaveCrypted::ScanForFiles(const std::string& save_directory, *size_files = size; } -CWiiSaveCrypted::~CWiiSaveCrypted() +WiiSave::~WiiSave() { } diff --git a/Source/Core/Core/HW/WiiSaveCrypted.h b/Source/Core/Core/HW/WiiSave.h similarity index 96% rename from Source/Core/Core/HW/WiiSaveCrypted.h rename to Source/Core/Core/HW/WiiSave.h index bd4f74838c..725179c330 100644 --- a/Source/Core/Core/HW/WiiSaveCrypted.h +++ b/Source/Core/Core/HW/WiiSave.h @@ -10,7 +10,7 @@ #include "Common/CommonTypes.h" -class CWiiSaveCrypted +class WiiSave { public: bool static ImportWiiSave(const std::string& filename); @@ -18,8 +18,8 @@ public: void static ExportAllSaves(); private: - CWiiSaveCrypted(const std::string& filename, u64 title_id = 0); - ~CWiiSaveCrypted(); + WiiSave(const std::string& filename, u64 title_id = 0); + ~WiiSave(); void ReadHDR(); void ReadBKHDR(); void WriteHDR(); diff --git a/Source/Core/DolphinQt2/GameList/GameList.cpp b/Source/Core/DolphinQt2/GameList/GameList.cpp index 76aef93609..05d0421561 100644 --- a/Source/Core/DolphinQt2/GameList/GameList.cpp +++ b/Source/Core/DolphinQt2/GameList/GameList.cpp @@ -20,7 +20,7 @@ #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/HW/DVD/DVDInterface.h" -#include "Core/HW/WiiSaveCrypted.h" +#include "Core/HW/WiiSave.h" #include "Core/WiiUtils.h" #include "DiscIO/Blob.h" #include "DiscIO/Enums.h" @@ -260,7 +260,7 @@ void GameList::ExportWiiSave() { QMessageBox result_dialog(this); - const bool success = CWiiSaveCrypted::ExportWiiSave(GetSelectedGame()->GetTitleID()); + const bool success = WiiSave::ExportWiiSave(GetSelectedGame()->GetTitleID()); result_dialog.setIcon(success ? QMessageBox::Information : QMessageBox::Critical); result_dialog.setText(success ? tr("Successfully exported save files") : diff --git a/Source/Core/DolphinQt2/MenuBar.cpp b/Source/Core/DolphinQt2/MenuBar.cpp index 7d4e46ceba..d9fb7a26c3 100644 --- a/Source/Core/DolphinQt2/MenuBar.cpp +++ b/Source/Core/DolphinQt2/MenuBar.cpp @@ -26,7 +26,7 @@ #include "Core/Core.h" #include "Core/Debugger/RSO.h" #include "Core/HLE/HLE.h" -#include "Core/HW/WiiSaveCrypted.h" +#include "Core/HW/WiiSave.h" #include "Core/HW/Wiimote.h" #include "Core/Host.h" #include "Core/IOS/ES/ES.h" @@ -897,12 +897,12 @@ void MenuBar::ImportWiiSave() "All Files (*)")); if (!file.isEmpty()) - CWiiSaveCrypted::ImportWiiSave(file.toStdString()); + WiiSave::ImportWiiSave(file.toStdString()); } void MenuBar::ExportWiiSaves() { - CWiiSaveCrypted::ExportAllSaves(); + WiiSave::ExportAllSaves(); } void MenuBar::CheckNAND() diff --git a/Source/Core/DolphinWX/FrameTools.cpp b/Source/Core/DolphinWX/FrameTools.cpp index d123d3ccca..ca14265e9d 100644 --- a/Source/Core/DolphinWX/FrameTools.cpp +++ b/Source/Core/DolphinWX/FrameTools.cpp @@ -45,7 +45,7 @@ #include "Core/HW/GCPad.h" #include "Core/HW/ProcessorInterface.h" #include "Core/HW/SI/SI_Device.h" -#include "Core/HW/WiiSaveCrypted.h" +#include "Core/HW/WiiSave.h" #include "Core/HW/Wiimote.h" #include "Core/Host.h" #include "Core/HotkeyManager.h" @@ -1204,7 +1204,7 @@ void CFrame::OnLoadGameCubeIPLEUR(wxCommandEvent&) void CFrame::OnExportAllSaves(wxCommandEvent& WXUNUSED(event)) { - CWiiSaveCrypted::ExportAllSaves(); + WiiSave::ExportAllSaves(); } void CFrame::OnImportSave(wxCommandEvent& WXUNUSED(event)) @@ -1215,7 +1215,7 @@ void CFrame::OnImportSave(wxCommandEvent& WXUNUSED(event)) wxFD_OPEN | wxFD_PREVIEW | wxFD_FILE_MUST_EXIST, this); if (!path.IsEmpty()) - CWiiSaveCrypted::ImportWiiSave(WxStrToStr(path)); + WiiSave::ImportWiiSave(WxStrToStr(path)); } void CFrame::OnShowCheatsWindow(wxCommandEvent& WXUNUSED(event)) diff --git a/Source/Core/DolphinWX/GameListCtrl.cpp b/Source/Core/DolphinWX/GameListCtrl.cpp index 30c973eb42..3fd57d8dd9 100644 --- a/Source/Core/DolphinWX/GameListCtrl.cpp +++ b/Source/Core/DolphinWX/GameListCtrl.cpp @@ -45,7 +45,7 @@ #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/HW/DVD/DVDInterface.h" -#include "Core/HW/WiiSaveCrypted.h" +#include "Core/HW/WiiSave.h" #include "Core/Movie.h" #include "Core/SysConf.h" #include "Core/TitleDatabase.h" @@ -988,7 +988,7 @@ void GameListCtrl::OnExportSave(wxCommandEvent& WXUNUSED(event)) { const UICommon::GameFile* iso = GetSelectedISO(); if (iso) - CWiiSaveCrypted::ExportWiiSave(iso->GetTitleID()); + WiiSave::ExportWiiSave(iso->GetTitleID()); } // Save this file as the default file From bae8bcde0a54d1a3bc529a0b43718e91898e9fac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sat, 12 May 2018 22:41:42 +0200 Subject: [PATCH 2/9] WiiSave: Do not expose internal constants --- Source/Core/Core/HW/WiiSave.cpp | 10 +++++----- Source/Core/Core/HW/WiiSave.h | 4 ---- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/Source/Core/Core/HW/WiiSave.cpp b/Source/Core/Core/HW/WiiSave.cpp index 5802c0faa4..2230132e13 100644 --- a/Source/Core/Core/HW/WiiSave.cpp +++ b/Source/Core/Core/HW/WiiSave.cpp @@ -31,11 +31,11 @@ #include "Common/StringUtil.h" #include "Common/Swap.h" -const u8 WiiSave::s_sd_key[16] = {0xAB, 0x01, 0xB9, 0xD8, 0xE1, 0x62, 0x2B, 0x08, - 0xAF, 0xBA, 0xD8, 0x4D, 0xBF, 0xC2, 0xA5, 0x5D}; -const u8 WiiSave::s_md5_blanker[16] = {0x0E, 0x65, 0x37, 0x81, 0x99, 0xBE, 0x45, 0x17, - 0xAB, 0x06, 0xEC, 0x22, 0x45, 0x1A, 0x57, 0x93}; -const u32 WiiSave::s_ng_id = 0x0403AC68; +constexpr u8 s_sd_key[16] = {0xAB, 0x01, 0xB9, 0xD8, 0xE1, 0x62, 0x2B, 0x08, + 0xAF, 0xBA, 0xD8, 0x4D, 0xBF, 0xC2, 0xA5, 0x5D}; +constexpr u8 s_md5_blanker[16] = {0x0E, 0x65, 0x37, 0x81, 0x99, 0xBE, 0x45, 0x17, + 0xAB, 0x06, 0xEC, 0x22, 0x45, 0x1A, 0x57, 0x93}; +constexpr u32 s_ng_id = 0x0403AC68; bool WiiSave::ImportWiiSave(const std::string& filename) { diff --git a/Source/Core/Core/HW/WiiSave.h b/Source/Core/Core/HW/WiiSave.h index 725179c330..52529320ac 100644 --- a/Source/Core/Core/HW/WiiSave.h +++ b/Source/Core/Core/HW/WiiSave.h @@ -34,10 +34,6 @@ private: void ScanForFiles(const std::string& save_directory, std::vector& file_list, u32* num_files, u32* size_files); - static const u8 s_sd_key[16]; - static const u8 s_md5_blanker[16]; - static const u32 s_ng_id; - mbedtls_aes_context m_aes_ctx; u8 m_sd_iv[0x10]; std::vector m_files_list; From fb39efbf90f7c228d99a4a0a80be1588cfebf41f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sat, 12 May 2018 22:47:49 +0200 Subject: [PATCH 3/9] WiiSave: Fix struct member naming --- Source/Core/Core/HW/WiiSave.cpp | 52 ++++++++++++++++----------------- Source/Core/Core/HW/WiiSave.h | 40 ++++++++++++------------- 2 files changed, 46 insertions(+), 46 deletions(-) diff --git a/Source/Core/Core/HW/WiiSave.cpp b/Source/Core/Core/HW/WiiSave.cpp index 2230132e13..2844f0c192 100644 --- a/Source/Core/Core/HW/WiiSave.cpp +++ b/Source/Core/Core/HW/WiiSave.cpp @@ -153,7 +153,7 @@ void WiiSave::ReadHDR() mbedtls_aes_crypt_cbc(&m_aes_ctx, MBEDTLS_AES_DECRYPT, HEADER_SZ, m_sd_iv, (const u8*)&m_encrypted_header, (u8*)&m_header); - u32 banner_size = Common::swap32(m_header.hdr.BannerSize); + u32 banner_size = Common::swap32(m_header.hdr.banner_size); if ((banner_size < FULL_BNR_MIN) || (banner_size > FULL_BNR_MAX) || (((banner_size - BNR_SZ) % ICON_SZ) != 0)) { @@ -161,12 +161,12 @@ void WiiSave::ReadHDR() m_valid = false; return; } - m_title_id = Common::swap64(m_header.hdr.SaveGameTitle); + m_title_id = Common::swap64(m_header.hdr.save_game_title); u8 md5_file[16]; u8 md5_calc[16]; - memcpy(md5_file, m_header.hdr.Md5, 0x10); - memcpy(m_header.hdr.Md5, s_md5_blanker, 0x10); + memcpy(md5_file, m_header.hdr.md5, 0x10); + memcpy(m_header.hdr.md5, s_md5_blanker, 0x10); mbedtls_md5((u8*)&m_header, HEADER_SZ, md5_calc); if (memcmp(md5_file, md5_calc, 0x10)) { @@ -189,7 +189,7 @@ void WiiSave::ReadHDR() { INFO_LOG(CONSOLE, "Creating file %s", banner_file_path.c_str()); File::IOFile banner_file(banner_file_path, "wb"); - banner_file.WriteBytes(m_header.BNR, banner_size); + banner_file.WriteBytes(m_header.banner, banner_size); } else { @@ -205,25 +205,25 @@ void WiiSave::WriteHDR() std::string banner_file_path = m_wii_title_path + "/banner.bin"; u32 banner_size = static_cast(File::GetSize(banner_file_path)); - m_header.hdr.BannerSize = Common::swap32(banner_size); + m_header.hdr.banner_size = Common::swap32(banner_size); - m_header.hdr.SaveGameTitle = Common::swap64(m_title_id); - memcpy(m_header.hdr.Md5, s_md5_blanker, 0x10); - m_header.hdr.Permissions = 0x3C; + m_header.hdr.save_game_title = Common::swap64(m_title_id); + memcpy(m_header.hdr.md5, s_md5_blanker, 0x10); + m_header.hdr.permissions = 0x3C; File::IOFile banner_file(banner_file_path, "rb"); - if (!banner_file.ReadBytes(m_header.BNR, banner_size)) + if (!banner_file.ReadBytes(m_header.banner, banner_size)) { ERROR_LOG(CONSOLE, "Failed to read banner.bin"); m_valid = false; return; } // remove nocopy flag - m_header.BNR[7] &= ~1; + m_header.banner[7] &= ~1; u8 md5_calc[16]; mbedtls_md5((u8*)&m_header, HEADER_SZ, md5_calc); - memcpy(m_header.hdr.Md5, md5_calc, 0x10); + memcpy(m_header.hdr.md5, md5_calc, 0x10); mbedtls_aes_crypt_cbc(&m_aes_ctx, MBEDTLS_AES_ENCRYPT, HEADER_SZ, m_sd_iv, (const u8*)&m_header, (u8*)&m_encrypted_header); @@ -265,20 +265,20 @@ void WiiSave::ReadBKHDR() return; } - m_files_list_size = Common::swap32(m_bk_hdr.numberOfFiles); - m_size_of_files = Common::swap32(m_bk_hdr.sizeOfFiles); - m_total_size = Common::swap32(m_bk_hdr.totalSize); + m_files_list_size = Common::swap32(m_bk_hdr.number_of_files); + m_size_of_files = Common::swap32(m_bk_hdr.size_of_files); + m_total_size = Common::swap32(m_bk_hdr.total_size); if (m_size_of_files + FULL_CERT_SZ != m_total_size) { WARN_LOG(CONSOLE, "Size(%x) + cert(%x) does not equal totalsize(%x)", m_size_of_files, FULL_CERT_SZ, m_total_size); } - if (m_title_id != Common::swap64(m_bk_hdr.SaveGameTitle)) + if (m_title_id != Common::swap64(m_bk_hdr.save_game_title)) { WARN_LOG(CONSOLE, "Encrypted title (%" PRIx64 ") does not match unencrypted title (%" PRIx64 ")", - m_title_id, Common::swap64(m_bk_hdr.SaveGameTitle)); + m_title_id, Common::swap64(m_bk_hdr.save_game_title)); } } @@ -293,11 +293,11 @@ void WiiSave::WriteBKHDR() memset(&m_bk_hdr, 0, BK_SZ); m_bk_hdr.size = Common::swap32(BK_LISTED_SZ); m_bk_hdr.magic = Common::swap32(BK_HDR_MAGIC); - m_bk_hdr.NGid = s_ng_id; - m_bk_hdr.numberOfFiles = Common::swap32(m_files_list_size); - m_bk_hdr.sizeOfFiles = Common::swap32(m_size_of_files); - m_bk_hdr.totalSize = Common::swap32(m_size_of_files + FULL_CERT_SZ); - m_bk_hdr.SaveGameTitle = Common::swap64(m_title_id); + m_bk_hdr.ngid = s_ng_id; + m_bk_hdr.number_of_files = Common::swap32(m_files_list_size); + m_bk_hdr.size_of_files = Common::swap32(m_size_of_files); + m_bk_hdr.total_size = Common::swap32(m_size_of_files + FULL_CERT_SZ); + m_bk_hdr.save_game_title = Common::swap64(m_title_id); File::IOFile data_file(m_encrypted_save_path, "ab"); if (!data_file.WriteBytes(&m_bk_hdr, BK_SZ)) @@ -364,7 +364,7 @@ void WiiSave::ImportWiiSaveFiles() break; } - memcpy(m_iv, file_hdr_tmp.IV, 0x10); + memcpy(m_iv, file_hdr_tmp.iv, 0x10); mbedtls_aes_crypt_cbc(&m_aes_ctx, MBEDTLS_AES_DECRYPT, file_size_rounded, m_iv, static_cast(file_data_enc.data()), file_data.data()); @@ -416,7 +416,7 @@ void WiiSave::ExportWiiSaveFiles() u32 file_size_rounded = Common::AlignUp(file_size, BLOCK_SZ); file_hdr_tmp.magic = Common::swap32(FILE_HDR_MAGIC); file_hdr_tmp.size = Common::swap32(file_size); - file_hdr_tmp.Permissions = 0x3c; + file_hdr_tmp.permissions = 0x3c; std::string name = Common::UnescapeFileName(m_files_list[i].substr(m_wii_title_path.length() + 1)); @@ -459,7 +459,7 @@ void WiiSave::ExportWiiSaveFiles() m_valid = false; } - mbedtls_aes_crypt_cbc(&m_aes_ctx, MBEDTLS_AES_ENCRYPT, file_size_rounded, file_hdr_tmp.IV, + mbedtls_aes_crypt_cbc(&m_aes_ctx, MBEDTLS_AES_ENCRYPT, file_size_rounded, file_hdr_tmp.iv, static_cast(file_data.data()), file_data_enc.data()); File::IOFile fpData_bin(m_encrypted_save_path, "ab"); @@ -514,7 +514,7 @@ void WiiSave::do_sig() generate_ecdsa(ap_sig, ap_sig + 30, ng_priv, hash); make_ec_cert(ap_cert, ap_sig, signer, name, ap_priv, 0); - data_size = Common::swap32(m_bk_hdr.sizeOfFiles) + 0x80; + data_size = Common::swap32(m_bk_hdr.size_of_files) + 0x80; File::IOFile data_file(m_encrypted_save_path, "rb"); if (!data_file) diff --git a/Source/Core/Core/HW/WiiSave.h b/Source/Core/Core/HW/WiiSave.h index 52529320ac..6e270a846d 100644 --- a/Source/Core/Core/HW/WiiSave.h +++ b/Source/Core/Core/HW/WiiSave.h @@ -76,37 +76,37 @@ private: #pragma pack(push, 1) - struct Data_Bin_HDR // encrypted + struct DataBinHeader // encrypted { - u64 SaveGameTitle; - u32 BannerSize; // (0x72A0 or 0xF0A0, also seen 0xBAA0) - u8 Permissions; + u64 save_game_title; + u32 banner_size; // (0x72A0 or 0xF0A0, also seen 0xBAA0) + u8 permissions; u8 unk1; // maybe permissions is a be16 - u8 Md5[0x10]; // md5 of plaintext header with md5 blanker applied + u8 md5[0x10]; // md5 of plaintext header with md5 blanker applied u16 unk2; }; - struct HEADER + struct Header { - Data_Bin_HDR hdr; - u8 BNR[FULL_BNR_MAX]; + DataBinHeader hdr; + u8 banner[FULL_BNR_MAX]; }; - struct BK_Header // Not encrypted + struct BkHeader // Not encrypted { u32 size; // 0x00000070 // u16 magic; // 'Bk' // u16 magic2; // or version (0x0001) u32 magic; // 0x426B0001 - u32 NGid; - u32 numberOfFiles; - u32 sizeOfFiles; + u32 ngid; + u32 number_of_files; + u32 size_of_files; u32 unk1; u32 unk2; - u32 totalSize; + u32 total_size; u8 unk3[64]; - u64 SaveGameTitle; - u8 MACaddress[6]; + u64 save_game_title; + u8 mac_address[6]; u8 padding[0x12]; }; @@ -114,16 +114,16 @@ private: { u32 magic; // 0x03adf17e u32 size; - u8 Permissions; + u8 permissions; u8 attrib; u8 type; // (1=file, 2=directory) u8 name[0x45]; - u8 IV[0x10]; + u8 iv[0x10]; u8 unk[0x20]; }; #pragma pack(pop) - HEADER m_header; - HEADER m_encrypted_header; - BK_Header m_bk_hdr; + Header m_header; + Header m_encrypted_header; + BkHeader m_bk_hdr; }; From 956df21bd7d45c1a945fcc5a958e16ec800bcec4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sat, 12 May 2018 23:15:27 +0200 Subject: [PATCH 4/9] WiiSave: Use Common::BigEndianValue to simplify parsing Gets rid of the need to manually cast when reading/writing, which is error prone and repetitive. --- Source/Core/Core/HW/WiiSave.cpp | 65 ++++++++++++++------------------- Source/Core/Core/HW/WiiSave.h | 33 ++++++++--------- 2 files changed, 43 insertions(+), 55 deletions(-) diff --git a/Source/Core/Core/HW/WiiSave.cpp b/Source/Core/Core/HW/WiiSave.cpp index 2844f0c192..71f6b93ffb 100644 --- a/Source/Core/Core/HW/WiiSave.cpp +++ b/Source/Core/Core/HW/WiiSave.cpp @@ -29,7 +29,6 @@ #include "Common/MsgHandler.h" #include "Common/NandPaths.h" #include "Common/StringUtil.h" -#include "Common/Swap.h" constexpr u8 s_sd_key[16] = {0xAB, 0x01, 0xB9, 0xD8, 0xE1, 0x62, 0x2B, 0x08, 0xAF, 0xBA, 0xD8, 0x4D, 0xBF, 0xC2, 0xA5, 0x5D}; @@ -153,7 +152,7 @@ void WiiSave::ReadHDR() mbedtls_aes_crypt_cbc(&m_aes_ctx, MBEDTLS_AES_DECRYPT, HEADER_SZ, m_sd_iv, (const u8*)&m_encrypted_header, (u8*)&m_header); - u32 banner_size = Common::swap32(m_header.hdr.banner_size); + u32 banner_size = m_header.hdr.banner_size; if ((banner_size < FULL_BNR_MIN) || (banner_size > FULL_BNR_MAX) || (((banner_size - BNR_SZ) % ICON_SZ) != 0)) { @@ -161,7 +160,7 @@ void WiiSave::ReadHDR() m_valid = false; return; } - m_title_id = Common::swap64(m_header.hdr.save_game_title); + m_title_id = m_header.hdr.save_game_title; u8 md5_file[16]; u8 md5_calc[16]; @@ -205,9 +204,9 @@ void WiiSave::WriteHDR() std::string banner_file_path = m_wii_title_path + "/banner.bin"; u32 banner_size = static_cast(File::GetSize(banner_file_path)); - m_header.hdr.banner_size = Common::swap32(banner_size); + m_header.hdr.banner_size = banner_size; - m_header.hdr.save_game_title = Common::swap64(m_title_id); + m_header.hdr.save_game_title = m_title_id; memcpy(m_header.hdr.md5, s_md5_blanker, 0x10); m_header.hdr.permissions = 0x3C; @@ -257,28 +256,24 @@ void WiiSave::ReadBKHDR() } fpData_bin.Close(); - if (m_bk_hdr.size != Common::swap32(BK_LISTED_SZ) || - m_bk_hdr.magic != Common::swap32(BK_HDR_MAGIC)) + if (m_bk_hdr.size != BK_LISTED_SZ || m_bk_hdr.magic != BK_HDR_MAGIC) { - ERROR_LOG(CONSOLE, "Invalid Size(%x) or Magic word (%x)", m_bk_hdr.size, m_bk_hdr.magic); + ERROR_LOG(CONSOLE, "Invalid Size(%x) or Magic word (%x)", u32(m_bk_hdr.size), + u32(m_bk_hdr.magic)); m_valid = false; return; } - m_files_list_size = Common::swap32(m_bk_hdr.number_of_files); - m_size_of_files = Common::swap32(m_bk_hdr.size_of_files); - m_total_size = Common::swap32(m_bk_hdr.total_size); - - if (m_size_of_files + FULL_CERT_SZ != m_total_size) + if (m_bk_hdr.size_of_files + FULL_CERT_SZ != m_bk_hdr.total_size) { - WARN_LOG(CONSOLE, "Size(%x) + cert(%x) does not equal totalsize(%x)", m_size_of_files, - FULL_CERT_SZ, m_total_size); + WARN_LOG(CONSOLE, "Size(%x) + cert(%x) does not equal totalsize(%x)", + u32(m_bk_hdr.size_of_files), FULL_CERT_SZ, u32(m_bk_hdr.total_size)); } - if (m_title_id != Common::swap64(m_bk_hdr.save_game_title)) + if (m_title_id != m_bk_hdr.save_game_title) { WARN_LOG(CONSOLE, "Encrypted title (%" PRIx64 ") does not match unencrypted title (%" PRIx64 ")", - m_title_id, Common::swap64(m_bk_hdr.save_game_title)); + m_title_id, u64(m_bk_hdr.save_game_title)); } } @@ -286,18 +281,16 @@ void WiiSave::WriteBKHDR() { if (!m_valid) return; - m_files_list_size = 0; - m_size_of_files = 0; - - ScanForFiles(m_wii_title_path, m_files_list, &m_files_list_size, &m_size_of_files); + u32 number_of_files = 0, size_of_files = 0; + ScanForFiles(m_wii_title_path, m_files_list, &number_of_files, &size_of_files); memset(&m_bk_hdr, 0, BK_SZ); - m_bk_hdr.size = Common::swap32(BK_LISTED_SZ); - m_bk_hdr.magic = Common::swap32(BK_HDR_MAGIC); + m_bk_hdr.size = BK_LISTED_SZ; + m_bk_hdr.magic = BK_HDR_MAGIC; m_bk_hdr.ngid = s_ng_id; - m_bk_hdr.number_of_files = Common::swap32(m_files_list_size); - m_bk_hdr.size_of_files = Common::swap32(m_size_of_files); - m_bk_hdr.total_size = Common::swap32(m_size_of_files + FULL_CERT_SZ); - m_bk_hdr.save_game_title = Common::swap64(m_title_id); + m_bk_hdr.number_of_files = number_of_files; + m_bk_hdr.size_of_files = size_of_files; + m_bk_hdr.total_size = size_of_files + FULL_CERT_SZ; + m_bk_hdr.save_game_title = m_title_id; File::IOFile data_file(m_encrypted_save_path, "ab"); if (!data_file.WriteBytes(&m_bk_hdr, BK_SZ)) @@ -324,11 +317,10 @@ void WiiSave::ImportWiiSaveFiles() FileHDR file_hdr_tmp; - for (u32 i = 0; i < m_files_list_size; ++i) + for (u32 i = 0; i < m_bk_hdr.number_of_files; ++i) { memset(&file_hdr_tmp, 0, FILE_HDR_SZ); memset(m_iv, 0, 0x10); - u32 file_size = 0; if (!data_file.ReadBytes(&file_hdr_tmp, FILE_HDR_SZ)) { @@ -336,7 +328,7 @@ void WiiSave::ImportWiiSaveFiles() m_valid = false; } - if (Common::swap32(file_hdr_tmp.magic) != FILE_HDR_MAGIC) + if (file_hdr_tmp.magic != FILE_HDR_MAGIC) { ERROR_LOG(CONSOLE, "Bad File Header"); break; @@ -352,8 +344,7 @@ void WiiSave::ImportWiiSaveFiles() const File::FileInfo file_info(file_path_full); if (file_hdr_tmp.type == 1) { - file_size = Common::swap32(file_hdr_tmp.size); - u32 file_size_rounded = Common::AlignUp(file_size, BLOCK_SZ); + u32 file_size_rounded = Common::AlignUp(file_hdr_tmp.size, BLOCK_SZ); std::vector file_data(file_size_rounded); std::vector file_data_enc(file_size_rounded); @@ -371,7 +362,7 @@ void WiiSave::ImportWiiSaveFiles() INFO_LOG(CONSOLE, "Creating file %s", file_path_full.c_str()); File::IOFile raw_save_file(file_path_full, "wb"); - raw_save_file.WriteBytes(file_data.data(), file_size); + raw_save_file.WriteBytes(file_data.data(), file_hdr_tmp.size); } else if (file_hdr_tmp.type == 2) { @@ -396,7 +387,7 @@ void WiiSave::ExportWiiSaveFiles() if (!m_valid) return; - for (u32 i = 0; i < m_files_list_size; i++) + for (u32 i = 0; i < m_bk_hdr.number_of_files; i++) { FileHDR file_hdr_tmp; memset(&file_hdr_tmp, 0, FILE_HDR_SZ); @@ -414,8 +405,8 @@ void WiiSave::ExportWiiSaveFiles() } u32 file_size_rounded = Common::AlignUp(file_size, BLOCK_SZ); - file_hdr_tmp.magic = Common::swap32(FILE_HDR_MAGIC); - file_hdr_tmp.size = Common::swap32(file_size); + file_hdr_tmp.magic = FILE_HDR_MAGIC; + file_hdr_tmp.size = file_size; file_hdr_tmp.permissions = 0x3c; std::string name = @@ -514,7 +505,7 @@ void WiiSave::do_sig() generate_ecdsa(ap_sig, ap_sig + 30, ng_priv, hash); make_ec_cert(ap_cert, ap_sig, signer, name, ap_priv, 0); - data_size = Common::swap32(m_bk_hdr.size_of_files) + 0x80; + data_size = m_bk_hdr.size_of_files + 0x80; File::IOFile data_file(m_encrypted_save_path, "rb"); if (!data_file) diff --git a/Source/Core/Core/HW/WiiSave.h b/Source/Core/Core/HW/WiiSave.h index 6e270a846d..513fdbff6f 100644 --- a/Source/Core/Core/HW/WiiSave.h +++ b/Source/Core/Core/HW/WiiSave.h @@ -9,6 +9,7 @@ #include #include "Common/CommonTypes.h" +#include "Common/Swap.h" class WiiSave { @@ -44,10 +45,6 @@ private: u8 m_iv[0x10]; - u32 m_files_list_size; - u32 m_size_of_files; - u32 m_total_size; - u64 m_title_id; bool m_valid; @@ -78,12 +75,12 @@ private: struct DataBinHeader // encrypted { - u64 save_game_title; - u32 banner_size; // (0x72A0 or 0xF0A0, also seen 0xBAA0) + Common::BigEndianValue save_game_title; + Common::BigEndianValue banner_size; // (0x72A0 or 0xF0A0, also seen 0xBAA0) u8 permissions; u8 unk1; // maybe permissions is a be16 u8 md5[0x10]; // md5 of plaintext header with md5 blanker applied - u16 unk2; + Common::BigEndianValue unk2; }; struct Header @@ -94,26 +91,26 @@ private: struct BkHeader // Not encrypted { - u32 size; // 0x00000070 + Common::BigEndianValue size; // 0x00000070 // u16 magic; // 'Bk' // u16 magic2; // or version (0x0001) - u32 magic; // 0x426B0001 - u32 ngid; - u32 number_of_files; - u32 size_of_files; - u32 unk1; - u32 unk2; - u32 total_size; + Common::BigEndianValue magic; // 0x426B0001 + Common::BigEndianValue ngid; + Common::BigEndianValue number_of_files; + Common::BigEndianValue size_of_files; + Common::BigEndianValue unk1; + Common::BigEndianValue unk2; + Common::BigEndianValue total_size; u8 unk3[64]; - u64 save_game_title; + Common::BigEndianValue save_game_title; u8 mac_address[6]; u8 padding[0x12]; }; struct FileHDR // encrypted { - u32 magic; // 0x03adf17e - u32 size; + Common::BigEndianValue magic; // 0x03adf17e + Common::BigEndianValue size; u8 permissions; u8 attrib; u8 type; // (1=file, 2=directory) From fbf36b85d21431a125ac895e58e7f19833c54f0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sat, 12 May 2018 23:17:08 +0200 Subject: [PATCH 5/9] WiiSave: Remove unused Extract() member function --- Source/Core/Core/HW/WiiSave.h | 1 - 1 file changed, 1 deletion(-) diff --git a/Source/Core/Core/HW/WiiSave.h b/Source/Core/Core/HW/WiiSave.h index 513fdbff6f..f948d42ba4 100644 --- a/Source/Core/Core/HW/WiiSave.h +++ b/Source/Core/Core/HW/WiiSave.h @@ -25,7 +25,6 @@ private: void ReadBKHDR(); void WriteHDR(); void WriteBKHDR(); - void Extract() {} void ImportWiiSaveFiles(); void ExportWiiSaveFiles(); void do_sig(); From 41c4486c653049464794d7831d479e91c26dd6c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sun, 13 May 2018 00:05:08 +0200 Subject: [PATCH 6/9] WiiSave: Clean up constructors Move the import/export operation into separate functions, as it doesn't really make sense for the constructor to do *everything*, including printing success/failure message boxes. The existing constructor was split into two: one that takes a path, and another taking a title ID. This makes it more obvious what is actually done when a path/TID is passed and also clarifies what parameters should be passed. (No more magic 0 or "" value.) --- Source/Core/Core/HW/WiiSave.cpp | 88 ++++++++++---------- Source/Core/Core/HW/WiiSave.h | 13 ++- Source/Core/DolphinQt2/GameList/GameList.cpp | 2 +- Source/Core/DolphinQt2/MenuBar.cpp | 4 +- Source/Core/DolphinWX/FrameTools.cpp | 4 +- Source/Core/DolphinWX/GameListCtrl.cpp | 2 +- 6 files changed, 59 insertions(+), 54 deletions(-) diff --git a/Source/Core/Core/HW/WiiSave.cpp b/Source/Core/Core/HW/WiiSave.cpp index 71f6b93ffb..89f33f8f94 100644 --- a/Source/Core/Core/HW/WiiSave.cpp +++ b/Source/Core/Core/HW/WiiSave.cpp @@ -36,27 +36,31 @@ constexpr u8 s_md5_blanker[16] = {0x0E, 0x65, 0x37, 0x81, 0x99, 0xBE, 0x45, 0x17 0xAB, 0x06, 0xEC, 0x22, 0x45, 0x1A, 0x57, 0x93}; constexpr u32 s_ng_id = 0x0403AC68; -bool WiiSave::ImportWiiSave(const std::string& filename) +bool WiiSave::Import(const std::string& filename) { - WiiSave save_file(filename); - return save_file.m_valid; + WiiSave save_file{filename}; + if (save_file.Import()) + { + SuccessAlertT("Successfully imported save file(s)"); + return true; + } + PanicAlertT("Import failed"); + return false; } -bool WiiSave::ExportWiiSave(u64 title_id) +bool WiiSave::Export(u64 title_id) { - WiiSave export_save("", title_id); - if (export_save.m_valid) + WiiSave export_save{title_id}; + if (export_save.Export()) { SuccessAlertT("Successfully exported file to %s", export_save.m_encrypted_save_path.c_str()); + return true; } - else - { - PanicAlertT("Export failed"); - } - return export_save.m_valid; + PanicAlertT("Export failed"); + return false; } -void WiiSave::ExportAllSaves() +void WiiSave::ExportAll() { std::string title_folder = File::GetUserPath(D_WIIROOT_IDX) + "/title"; std::vector titles; @@ -88,49 +92,45 @@ void WiiSave::ExportAllSaves() u32 success = 0; for (const u64& title : titles) { - WiiSave export_save{"", title}; - if (export_save.m_valid) + WiiSave export_save{title}; + if (export_save.Export()) success++; } SuccessAlertT("Successfully exported %u save(s) to %s", success, (File::GetUserPath(D_USER_IDX) + "private/wii/title/").c_str()); } -WiiSave::WiiSave(const std::string& filename, u64 title_id) - : m_encrypted_save_path(filename), m_title_id(title_id) +WiiSave::WiiSave(std::string filename) : m_encrypted_save_path(std::move(filename)), m_valid{true} { memcpy(m_sd_iv, "\x21\x67\x12\xE6\xAA\x1F\x68\x9F\x95\xC5\xA2\x23\x24\xDC\x6A\x98", 0x10); + mbedtls_aes_setkey_dec(&m_aes_ctx, s_sd_key, 128); +} - if (!title_id) // Import - { - mbedtls_aes_setkey_dec(&m_aes_ctx, s_sd_key, 128); +bool WiiSave::Import() +{ + ReadHDR(); + ReadBKHDR(); + ImportWiiSaveFiles(); + // TODO: check_sig() + return m_valid; +} + +WiiSave::WiiSave(u64 title_id) : m_title_id{title_id} +{ + memcpy(m_sd_iv, "\x21\x67\x12\xE6\xAA\x1F\x68\x9F\x95\xC5\xA2\x23\x24\xDC\x6A\x98", 0x10); + mbedtls_aes_setkey_enc(&m_aes_ctx, s_sd_key, 128); + + if (getPaths(true)) m_valid = true; - ReadHDR(); - ReadBKHDR(); - ImportWiiSaveFiles(); - // TODO: check_sig() - if (m_valid) - { - SuccessAlertT("Successfully imported save file(s)"); - } - else - { - PanicAlertT("Import failed"); - } - } - else - { - mbedtls_aes_setkey_enc(&m_aes_ctx, s_sd_key, 128); +} - if (getPaths(true)) - { - m_valid = true; - WriteHDR(); - WriteBKHDR(); - ExportWiiSaveFiles(); - do_sig(); - } - } +bool WiiSave::Export() +{ + WriteHDR(); + WriteBKHDR(); + ExportWiiSaveFiles(); + do_sig(); + return m_valid; } void WiiSave::ReadHDR() diff --git a/Source/Core/Core/HW/WiiSave.h b/Source/Core/Core/HW/WiiSave.h index f948d42ba4..160c2b5452 100644 --- a/Source/Core/Core/HW/WiiSave.h +++ b/Source/Core/Core/HW/WiiSave.h @@ -14,13 +14,18 @@ class WiiSave { public: - bool static ImportWiiSave(const std::string& filename); - bool static ExportWiiSave(u64 title_id); - void static ExportAllSaves(); + static bool Import(const std::string& filename); + static bool Export(u64 title_id); + static void ExportAll(); private: - WiiSave(const std::string& filename, u64 title_id = 0); + explicit WiiSave(std::string filename); + explicit WiiSave(u64 title_id); ~WiiSave(); + + bool Import(); + bool Export(); + void ReadHDR(); void ReadBKHDR(); void WriteHDR(); diff --git a/Source/Core/DolphinQt2/GameList/GameList.cpp b/Source/Core/DolphinQt2/GameList/GameList.cpp index 05d0421561..e3b21af6f7 100644 --- a/Source/Core/DolphinQt2/GameList/GameList.cpp +++ b/Source/Core/DolphinQt2/GameList/GameList.cpp @@ -260,7 +260,7 @@ void GameList::ExportWiiSave() { QMessageBox result_dialog(this); - const bool success = WiiSave::ExportWiiSave(GetSelectedGame()->GetTitleID()); + const bool success = WiiSave::Export(GetSelectedGame()->GetTitleID()); result_dialog.setIcon(success ? QMessageBox::Information : QMessageBox::Critical); result_dialog.setText(success ? tr("Successfully exported save files") : diff --git a/Source/Core/DolphinQt2/MenuBar.cpp b/Source/Core/DolphinQt2/MenuBar.cpp index d9fb7a26c3..adadc6301a 100644 --- a/Source/Core/DolphinQt2/MenuBar.cpp +++ b/Source/Core/DolphinQt2/MenuBar.cpp @@ -897,12 +897,12 @@ void MenuBar::ImportWiiSave() "All Files (*)")); if (!file.isEmpty()) - WiiSave::ImportWiiSave(file.toStdString()); + WiiSave::Import(file.toStdString()); } void MenuBar::ExportWiiSaves() { - WiiSave::ExportAllSaves(); + WiiSave::ExportAll(); } void MenuBar::CheckNAND() diff --git a/Source/Core/DolphinWX/FrameTools.cpp b/Source/Core/DolphinWX/FrameTools.cpp index ca14265e9d..da34972d94 100644 --- a/Source/Core/DolphinWX/FrameTools.cpp +++ b/Source/Core/DolphinWX/FrameTools.cpp @@ -1204,7 +1204,7 @@ void CFrame::OnLoadGameCubeIPLEUR(wxCommandEvent&) void CFrame::OnExportAllSaves(wxCommandEvent& WXUNUSED(event)) { - WiiSave::ExportAllSaves(); + WiiSave::ExportAll(); } void CFrame::OnImportSave(wxCommandEvent& WXUNUSED(event)) @@ -1215,7 +1215,7 @@ void CFrame::OnImportSave(wxCommandEvent& WXUNUSED(event)) wxFD_OPEN | wxFD_PREVIEW | wxFD_FILE_MUST_EXIST, this); if (!path.IsEmpty()) - WiiSave::ImportWiiSave(WxStrToStr(path)); + WiiSave::Import(WxStrToStr(path)); } void CFrame::OnShowCheatsWindow(wxCommandEvent& WXUNUSED(event)) diff --git a/Source/Core/DolphinWX/GameListCtrl.cpp b/Source/Core/DolphinWX/GameListCtrl.cpp index 3fd57d8dd9..d0d9dfeeac 100644 --- a/Source/Core/DolphinWX/GameListCtrl.cpp +++ b/Source/Core/DolphinWX/GameListCtrl.cpp @@ -988,7 +988,7 @@ void GameListCtrl::OnExportSave(wxCommandEvent& WXUNUSED(event)) { const UICommon::GameFile* iso = GetSelectedISO(); if (iso) - WiiSave::ExportWiiSave(iso->GetTitleID()); + WiiSave::Export(iso->GetTitleID()); } // Save this file as the default file From a93d816c283de6972e3994a7e89f3c423f6afef6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sun, 13 May 2018 13:18:19 +0200 Subject: [PATCH 7/9] WiiSave: Move dialogs to UI code This moves the result dialogs to DolphinQt2, since WiiSave should not really be responsible for interacting with the user as a simple Wii save importing/exporting class. This also fixes Wii save import/export showing result dialogs twice, once from WiiSave, and another time from DolphinQt2. --- Source/Core/Core/HW/WiiSave.cpp | 28 +++++--------------- Source/Core/Core/HW/WiiSave.h | 9 +++++-- Source/Core/DolphinQt2/GameList/GameList.cpp | 10 ++++--- Source/Core/DolphinQt2/MenuBar.cpp | 14 +++++++--- 4 files changed, 31 insertions(+), 30 deletions(-) diff --git a/Source/Core/Core/HW/WiiSave.cpp b/Source/Core/Core/HW/WiiSave.cpp index 89f33f8f94..a8fce79221 100644 --- a/Source/Core/Core/HW/WiiSave.cpp +++ b/Source/Core/Core/HW/WiiSave.cpp @@ -39,28 +39,16 @@ constexpr u32 s_ng_id = 0x0403AC68; bool WiiSave::Import(const std::string& filename) { WiiSave save_file{filename}; - if (save_file.Import()) - { - SuccessAlertT("Successfully imported save file(s)"); - return true; - } - PanicAlertT("Import failed"); - return false; + return save_file.Import(); } -bool WiiSave::Export(u64 title_id) +std::string WiiSave::Export(u64 title_id) { WiiSave export_save{title_id}; - if (export_save.Export()) - { - SuccessAlertT("Successfully exported file to %s", export_save.m_encrypted_save_path.c_str()); - return true; - } - PanicAlertT("Export failed"); - return false; + return export_save.Export() ? export_save.m_encrypted_save_path : ""; } -void WiiSave::ExportAll() +std::pair WiiSave::ExportAll() { std::string title_folder = File::GetUserPath(D_WIIROOT_IDX) + "/title"; std::vector titles; @@ -88,16 +76,14 @@ void WiiSave::ExportAll() } } } - SuccessAlertT("Found %zu save file(s)", titles.size()); - u32 success = 0; + size_t exported_save_count = 0; for (const u64& title : titles) { WiiSave export_save{title}; if (export_save.Export()) - success++; + ++exported_save_count; } - SuccessAlertT("Successfully exported %u save(s) to %s", success, - (File::GetUserPath(D_USER_IDX) + "private/wii/title/").c_str()); + return {exported_save_count, File::GetUserPath(D_USER_IDX) + "private/wii/title/"}; } WiiSave::WiiSave(std::string filename) : m_encrypted_save_path(std::move(filename)), m_valid{true} diff --git a/Source/Core/Core/HW/WiiSave.h b/Source/Core/Core/HW/WiiSave.h index 160c2b5452..0a4d993a29 100644 --- a/Source/Core/Core/HW/WiiSave.h +++ b/Source/Core/Core/HW/WiiSave.h @@ -6,6 +6,7 @@ #include #include +#include #include #include "Common/CommonTypes.h" @@ -14,9 +15,13 @@ class WiiSave { public: + /// Import a save into the NAND from a .bin file. static bool Import(const std::string& filename); - static bool Export(u64 title_id); - static void ExportAll(); + /// Export a save to a .bin file. Returns the path to the .bin. + static std::string Export(u64 title_id); + /// Export all saves that are in the NAND. Returns the number of exported saves and a path + /// to the .bins. + static std::pair ExportAll(); private: explicit WiiSave(std::string filename); diff --git a/Source/Core/DolphinQt2/GameList/GameList.cpp b/Source/Core/DolphinQt2/GameList/GameList.cpp index e3b21af6f7..184f45622a 100644 --- a/Source/Core/DolphinQt2/GameList/GameList.cpp +++ b/Source/Core/DolphinQt2/GameList/GameList.cpp @@ -260,11 +260,13 @@ void GameList::ExportWiiSave() { QMessageBox result_dialog(this); - const bool success = WiiSave::Export(GetSelectedGame()->GetTitleID()); + const QString bin_path = QString::fromStdString(WiiSave::Export(GetSelectedGame()->GetTitleID())); - result_dialog.setIcon(success ? QMessageBox::Information : QMessageBox::Critical); - result_dialog.setText(success ? tr("Successfully exported save files") : - tr("Failed to export save files!")); + result_dialog.setIcon(!bin_path.isEmpty() ? QMessageBox::Information : QMessageBox::Critical); + if (!bin_path.isEmpty()) + result_dialog.setText(tr("Successfully exported save files to %1").arg(bin_path)); + else + result_dialog.setText(tr("Failed to export save files.")); result_dialog.exec(); } diff --git a/Source/Core/DolphinQt2/MenuBar.cpp b/Source/Core/DolphinQt2/MenuBar.cpp index adadc6301a..61df3f967c 100644 --- a/Source/Core/DolphinQt2/MenuBar.cpp +++ b/Source/Core/DolphinQt2/MenuBar.cpp @@ -896,13 +896,21 @@ void MenuBar::ImportWiiSave() tr("Wii save files (*.bin);;" "All Files (*)")); - if (!file.isEmpty()) - WiiSave::Import(file.toStdString()); + if (file.isEmpty()) + return; + + if (WiiSave::Import(file.toStdString())) + QMessageBox::information(this, tr("Save Import"), tr("Successfully imported save files.")); + else + QMessageBox::critical(this, tr("Save Import"), tr("Failed to import save files.")); } void MenuBar::ExportWiiSaves() { - WiiSave::ExportAll(); + const std::pair result = WiiSave::ExportAll(); + QMessageBox::information(this, tr("Save Export"), + tr("Exported %n save(s) to %1", "", static_cast(result.first)) + .arg(QString::fromStdString(result.second))); } void MenuBar::CheckNAND() From 87e5cd73dc38a664f14b89d29dfb2908c84b9a80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sun, 13 May 2018 13:34:02 +0200 Subject: [PATCH 8/9] WiiSave: Use std::array instead of C arrays Makes copying, comparing more readable --- Source/Core/Core/HW/WiiSave.cpp | 67 +++++++++++++++++---------------- Source/Core/Core/HW/WiiSave.h | 21 ++++++----- 2 files changed, 46 insertions(+), 42 deletions(-) diff --git a/Source/Core/Core/HW/WiiSave.cpp b/Source/Core/Core/HW/WiiSave.cpp index a8fce79221..7314b28b5f 100644 --- a/Source/Core/Core/HW/WiiSave.cpp +++ b/Source/Core/Core/HW/WiiSave.cpp @@ -30,10 +30,14 @@ #include "Common/NandPaths.h" #include "Common/StringUtil.h" -constexpr u8 s_sd_key[16] = {0xAB, 0x01, 0xB9, 0xD8, 0xE1, 0x62, 0x2B, 0x08, - 0xAF, 0xBA, 0xD8, 0x4D, 0xBF, 0xC2, 0xA5, 0x5D}; -constexpr u8 s_md5_blanker[16] = {0x0E, 0x65, 0x37, 0x81, 0x99, 0xBE, 0x45, 0x17, - 0xAB, 0x06, 0xEC, 0x22, 0x45, 0x1A, 0x57, 0x93}; +using Md5 = std::array; + +constexpr std::array s_sd_initial_iv{{0x21, 0x67, 0x12, 0xE6, 0xAA, 0x1F, 0x68, 0x9F, + 0x95, 0xC5, 0xA2, 0x23, 0x24, 0xDC, 0x6A, 0x98}}; +constexpr std::array s_sd_key{{0xAB, 0x01, 0xB9, 0xD8, 0xE1, 0x62, 0x2B, 0x08, 0xAF, 0xBA, + 0xD8, 0x4D, 0xBF, 0xC2, 0xA5, 0x5D}}; +constexpr Md5 s_md5_blanker{{0x0E, 0x65, 0x37, 0x81, 0x99, 0xBE, 0x45, 0x17, 0xAB, 0x06, 0xEC, 0x22, + 0x45, 0x1A, 0x57, 0x93}}; constexpr u32 s_ng_id = 0x0403AC68; bool WiiSave::Import(const std::string& filename) @@ -86,10 +90,10 @@ std::pair WiiSave::ExportAll() return {exported_save_count, File::GetUserPath(D_USER_IDX) + "private/wii/title/"}; } -WiiSave::WiiSave(std::string filename) : m_encrypted_save_path(std::move(filename)), m_valid{true} +WiiSave::WiiSave(std::string filename) + : m_sd_iv{s_sd_initial_iv}, m_encrypted_save_path(std::move(filename)), m_valid{true} { - memcpy(m_sd_iv, "\x21\x67\x12\xE6\xAA\x1F\x68\x9F\x95\xC5\xA2\x23\x24\xDC\x6A\x98", 0x10); - mbedtls_aes_setkey_dec(&m_aes_ctx, s_sd_key, 128); + mbedtls_aes_setkey_dec(&m_aes_ctx, s_sd_key.data(), 128); } bool WiiSave::Import() @@ -101,10 +105,9 @@ bool WiiSave::Import() return m_valid; } -WiiSave::WiiSave(u64 title_id) : m_title_id{title_id} +WiiSave::WiiSave(u64 title_id) : m_sd_iv{s_sd_initial_iv}, m_title_id{title_id} { - memcpy(m_sd_iv, "\x21\x67\x12\xE6\xAA\x1F\x68\x9F\x95\xC5\xA2\x23\x24\xDC\x6A\x98", 0x10); - mbedtls_aes_setkey_enc(&m_aes_ctx, s_sd_key, 128); + mbedtls_aes_setkey_enc(&m_aes_ctx, s_sd_key.data(), 128); if (getPaths(true)) m_valid = true; @@ -136,7 +139,7 @@ void WiiSave::ReadHDR() } data_file.Close(); - mbedtls_aes_crypt_cbc(&m_aes_ctx, MBEDTLS_AES_DECRYPT, HEADER_SZ, m_sd_iv, + mbedtls_aes_crypt_cbc(&m_aes_ctx, MBEDTLS_AES_DECRYPT, HEADER_SZ, m_sd_iv.data(), (const u8*)&m_encrypted_header, (u8*)&m_header); u32 banner_size = m_header.hdr.banner_size; if ((banner_size < FULL_BNR_MIN) || (banner_size > FULL_BNR_MAX) || @@ -148,16 +151,15 @@ void WiiSave::ReadHDR() } m_title_id = m_header.hdr.save_game_title; - u8 md5_file[16]; - u8 md5_calc[16]; - memcpy(md5_file, m_header.hdr.md5, 0x10); - memcpy(m_header.hdr.md5, s_md5_blanker, 0x10); - mbedtls_md5((u8*)&m_header, HEADER_SZ, md5_calc); - if (memcmp(md5_file, md5_calc, 0x10)) + Md5 md5_file = m_header.hdr.md5; + m_header.hdr.md5 = s_md5_blanker; + Md5 md5_calc; + mbedtls_md5((u8*)&m_header, HEADER_SZ, md5_calc.data()); + if (md5_file == md5_calc) { ERROR_LOG(CONSOLE, "MD5 mismatch\n %016" PRIx64 "%016" PRIx64 " != %016" PRIx64 "%016" PRIx64, - Common::swap64(md5_file), Common::swap64(md5_file + 8), Common::swap64(md5_calc), - Common::swap64(md5_calc + 8)); + Common::swap64(md5_file.data()), Common::swap64(md5_file.data() + 8), + Common::swap64(md5_calc.data()), Common::swap64(md5_calc.data() + 8)); m_valid = false; } @@ -193,7 +195,7 @@ void WiiSave::WriteHDR() m_header.hdr.banner_size = banner_size; m_header.hdr.save_game_title = m_title_id; - memcpy(m_header.hdr.md5, s_md5_blanker, 0x10); + m_header.hdr.md5 = s_md5_blanker; m_header.hdr.permissions = 0x3C; File::IOFile banner_file(banner_file_path, "rb"); @@ -206,12 +208,12 @@ void WiiSave::WriteHDR() // remove nocopy flag m_header.banner[7] &= ~1; - u8 md5_calc[16]; - mbedtls_md5((u8*)&m_header, HEADER_SZ, md5_calc); - memcpy(m_header.hdr.md5, md5_calc, 0x10); + Md5 md5_calc; + mbedtls_md5((u8*)&m_header, HEADER_SZ, md5_calc.data()); + m_header.hdr.md5 = std::move(md5_calc); - mbedtls_aes_crypt_cbc(&m_aes_ctx, MBEDTLS_AES_ENCRYPT, HEADER_SZ, m_sd_iv, (const u8*)&m_header, - (u8*)&m_encrypted_header); + mbedtls_aes_crypt_cbc(&m_aes_ctx, MBEDTLS_AES_ENCRYPT, HEADER_SZ, m_sd_iv.data(), + (const u8*)&m_header, (u8*)&m_encrypted_header); File::IOFile data_file(m_encrypted_save_path, "wb"); if (!data_file.WriteBytes(&m_encrypted_header, HEADER_SZ)) @@ -306,7 +308,7 @@ void WiiSave::ImportWiiSaveFiles() for (u32 i = 0; i < m_bk_hdr.number_of_files; ++i) { memset(&file_hdr_tmp, 0, FILE_HDR_SZ); - memset(m_iv, 0, 0x10); + m_iv.fill(0); if (!data_file.ReadBytes(&file_hdr_tmp, FILE_HDR_SZ)) { @@ -323,7 +325,7 @@ void WiiSave::ImportWiiSaveFiles() { // Allows files in subfolders to be escaped properly (ex: "nocopy/data00") // Special characters in path components will be escaped such as /../ - std::string file_path = Common::EscapePath(reinterpret_cast(file_hdr_tmp.name)); + std::string file_path = Common::EscapePath(file_hdr_tmp.name.data()); std::string file_path_full = m_wii_title_path + '/' + file_path; File::CreateFullPath(file_path_full); @@ -341,8 +343,8 @@ void WiiSave::ImportWiiSaveFiles() break; } - memcpy(m_iv, file_hdr_tmp.iv, 0x10); - mbedtls_aes_crypt_cbc(&m_aes_ctx, MBEDTLS_AES_DECRYPT, file_size_rounded, m_iv, + m_iv = file_hdr_tmp.iv; + mbedtls_aes_crypt_cbc(&m_aes_ctx, MBEDTLS_AES_DECRYPT, file_size_rounded, m_iv.data(), static_cast(file_data_enc.data()), file_data.data()); INFO_LOG(CONSOLE, "Creating file %s", file_path_full.c_str()); @@ -405,7 +407,7 @@ void WiiSave::ExportWiiSaveFiles() m_valid = false; return; } - strncpy((char*)file_hdr_tmp.name, name.c_str(), sizeof(file_hdr_tmp.name)); + std::strncpy(file_hdr_tmp.name.data(), name.c_str(), file_hdr_tmp.name.size()); { File::IOFile fpData_bin(m_encrypted_save_path, "ab"); @@ -436,8 +438,9 @@ void WiiSave::ExportWiiSaveFiles() m_valid = false; } - mbedtls_aes_crypt_cbc(&m_aes_ctx, MBEDTLS_AES_ENCRYPT, file_size_rounded, file_hdr_tmp.iv, - static_cast(file_data.data()), file_data_enc.data()); + mbedtls_aes_crypt_cbc(&m_aes_ctx, MBEDTLS_AES_ENCRYPT, file_size_rounded, + file_hdr_tmp.iv.data(), static_cast(file_data.data()), + file_data_enc.data()); File::IOFile fpData_bin(m_encrypted_save_path, "ab"); if (!fpData_bin.WriteBytes(file_data_enc.data(), file_size_rounded)) diff --git a/Source/Core/Core/HW/WiiSave.h b/Source/Core/Core/HW/WiiSave.h index 0a4d993a29..dbc33b446b 100644 --- a/Source/Core/Core/HW/WiiSave.h +++ b/Source/Core/Core/HW/WiiSave.h @@ -4,6 +4,7 @@ #pragma once +#include #include #include #include @@ -45,14 +46,14 @@ private: u32* num_files, u32* size_files); mbedtls_aes_context m_aes_ctx; - u8 m_sd_iv[0x10]; + std::array m_sd_iv; std::vector m_files_list; std::string m_encrypted_save_path; std::string m_wii_title_path; - u8 m_iv[0x10]; + std::array m_iv; u64 m_title_id; @@ -87,8 +88,8 @@ private: Common::BigEndianValue save_game_title; Common::BigEndianValue banner_size; // (0x72A0 or 0xF0A0, also seen 0xBAA0) u8 permissions; - u8 unk1; // maybe permissions is a be16 - u8 md5[0x10]; // md5 of plaintext header with md5 blanker applied + u8 unk1; // maybe permissions is a be16 + std::array md5; // md5 of plaintext header with md5 blanker applied Common::BigEndianValue unk2; }; @@ -110,10 +111,10 @@ private: Common::BigEndianValue unk1; Common::BigEndianValue unk2; Common::BigEndianValue total_size; - u8 unk3[64]; + std::array unk3; Common::BigEndianValue save_game_title; - u8 mac_address[6]; - u8 padding[0x12]; + std::array mac_address; + std::array padding; }; struct FileHDR // encrypted @@ -123,9 +124,9 @@ private: u8 permissions; u8 attrib; u8 type; // (1=file, 2=directory) - u8 name[0x45]; - u8 iv[0x10]; - u8 unk[0x20]; + std::array name; + std::array iv; + std::array unk; }; #pragma pack(pop) From 80b3d7ccb8a3199b7f9a98cc2d3e7a92a0b1842e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sun, 13 May 2018 15:34:30 +0200 Subject: [PATCH 9/9] WiiSave: Allow users to specify export directory Export and ExportAll now open a directory picker (that defaults to the previous default directory, i.e. the Dolphin user dir). Also removes the need to return the path in the export functions since the user knows which path they chose. --- Source/Core/Core/HW/WiiSave.cpp | 26 +++++++++----------- Source/Core/Core/HW/WiiSave.h | 13 +++++----- Source/Core/DolphinQt2/GameList/GameList.cpp | 16 ++++++------ Source/Core/DolphinQt2/MenuBar.cpp | 11 ++++++--- Source/Core/DolphinWX/FrameTools.cpp | 2 +- Source/Core/DolphinWX/GameListCtrl.cpp | 2 +- 6 files changed, 35 insertions(+), 35 deletions(-) diff --git a/Source/Core/Core/HW/WiiSave.cpp b/Source/Core/Core/HW/WiiSave.cpp index 7314b28b5f..5909c00e7f 100644 --- a/Source/Core/Core/HW/WiiSave.cpp +++ b/Source/Core/Core/HW/WiiSave.cpp @@ -40,19 +40,19 @@ constexpr Md5 s_md5_blanker{{0x0E, 0x65, 0x37, 0x81, 0x99, 0xBE, 0x45, 0x17, 0xA 0x45, 0x1A, 0x57, 0x93}}; constexpr u32 s_ng_id = 0x0403AC68; -bool WiiSave::Import(const std::string& filename) +bool WiiSave::Import(std::string filename) { - WiiSave save_file{filename}; + WiiSave save_file{std::move(filename)}; return save_file.Import(); } -std::string WiiSave::Export(u64 title_id) +bool WiiSave::Export(u64 title_id, std::string export_path) { - WiiSave export_save{title_id}; - return export_save.Export() ? export_save.m_encrypted_save_path : ""; + WiiSave export_save{title_id, std::move(export_path)}; + return export_save.Export(); } -std::pair WiiSave::ExportAll() +size_t WiiSave::ExportAll(std::string export_path) { std::string title_folder = File::GetUserPath(D_WIIROOT_IDX) + "/title"; std::vector titles; @@ -83,11 +83,11 @@ std::pair WiiSave::ExportAll() size_t exported_save_count = 0; for (const u64& title : titles) { - WiiSave export_save{title}; + WiiSave export_save{title, export_path}; if (export_save.Export()) ++exported_save_count; } - return {exported_save_count, File::GetUserPath(D_USER_IDX) + "private/wii/title/"}; + return exported_save_count; } WiiSave::WiiSave(std::string filename) @@ -105,7 +105,8 @@ bool WiiSave::Import() return m_valid; } -WiiSave::WiiSave(u64 title_id) : m_sd_iv{s_sd_initial_iv}, m_title_id{title_id} +WiiSave::WiiSave(u64 title_id, std::string export_path) + : m_sd_iv{s_sd_initial_iv}, m_encrypted_save_path(std::move(export_path)), m_title_id{title_id} { mbedtls_aes_setkey_enc(&m_aes_ctx, s_sd_key.data(), 128); @@ -571,12 +572,7 @@ bool WiiSave::getPaths(bool for_export) ERROR_LOG(CONSOLE, "No banner file found for title %s", game_id); return false; } - if (m_encrypted_save_path.length() == 0) - { - // If no path was passed, use User folder - m_encrypted_save_path = File::GetUserPath(D_USER_IDX); - } - m_encrypted_save_path += StringFromFormat("private/wii/title/%s/data.bin", game_id); + m_encrypted_save_path += StringFromFormat("/private/wii/title/%s/data.bin", game_id); File::CreateFullPath(m_encrypted_save_path); } else diff --git a/Source/Core/Core/HW/WiiSave.h b/Source/Core/Core/HW/WiiSave.h index dbc33b446b..995082eebd 100644 --- a/Source/Core/Core/HW/WiiSave.h +++ b/Source/Core/Core/HW/WiiSave.h @@ -17,16 +17,15 @@ class WiiSave { public: /// Import a save into the NAND from a .bin file. - static bool Import(const std::string& filename); - /// Export a save to a .bin file. Returns the path to the .bin. - static std::string Export(u64 title_id); - /// Export all saves that are in the NAND. Returns the number of exported saves and a path - /// to the .bins. - static std::pair ExportAll(); + static bool Import(std::string filename); + /// Export a save to a .bin file. + static bool Export(u64 title_id, std::string export_path); + /// Export all saves that are in the NAND. Returns the number of exported saves. + static size_t ExportAll(std::string export_path); private: explicit WiiSave(std::string filename); - explicit WiiSave(u64 title_id); + explicit WiiSave(u64 title_id, std::string export_path); ~WiiSave(); bool Import(); diff --git a/Source/Core/DolphinQt2/GameList/GameList.cpp b/Source/Core/DolphinQt2/GameList/GameList.cpp index 184f45622a..00e30abace 100644 --- a/Source/Core/DolphinQt2/GameList/GameList.cpp +++ b/Source/Core/DolphinQt2/GameList/GameList.cpp @@ -258,16 +258,16 @@ void GameList::OpenProperties() void GameList::ExportWiiSave() { - QMessageBox result_dialog(this); + const QString export_dir = QFileDialog::getExistingDirectory( + this, tr("Select Export Directory"), QString::fromStdString(File::GetUserPath(D_USER_IDX)), + QFileDialog::ShowDirsOnly); + if (export_dir.isEmpty()) + return; - const QString bin_path = QString::fromStdString(WiiSave::Export(GetSelectedGame()->GetTitleID())); - - result_dialog.setIcon(!bin_path.isEmpty() ? QMessageBox::Information : QMessageBox::Critical); - if (!bin_path.isEmpty()) - result_dialog.setText(tr("Successfully exported save files to %1").arg(bin_path)); + if (WiiSave::Export(GetSelectedGame()->GetTitleID(), export_dir.toStdString())) + QMessageBox::information(this, tr("Save Export"), tr("Successfully exported save files")); else - result_dialog.setText(tr("Failed to export save files.")); - result_dialog.exec(); + QMessageBox::critical(this, tr("Save Export"), tr("Failed to export save files.")); } void GameList::OpenWiki() diff --git a/Source/Core/DolphinQt2/MenuBar.cpp b/Source/Core/DolphinQt2/MenuBar.cpp index 61df3f967c..5f939fb087 100644 --- a/Source/Core/DolphinQt2/MenuBar.cpp +++ b/Source/Core/DolphinQt2/MenuBar.cpp @@ -907,10 +907,15 @@ void MenuBar::ImportWiiSave() void MenuBar::ExportWiiSaves() { - const std::pair result = WiiSave::ExportAll(); + const QString export_dir = QFileDialog::getExistingDirectory( + this, tr("Select Export Directory"), QString::fromStdString(File::GetUserPath(D_USER_IDX)), + QFileDialog::ShowDirsOnly); + if (export_dir.isEmpty()) + return; + + const size_t count = WiiSave::ExportAll(export_dir.toStdString()); QMessageBox::information(this, tr("Save Export"), - tr("Exported %n save(s) to %1", "", static_cast(result.first)) - .arg(QString::fromStdString(result.second))); + tr("Exported %n save(s)", "", static_cast(count))); } void MenuBar::CheckNAND() diff --git a/Source/Core/DolphinWX/FrameTools.cpp b/Source/Core/DolphinWX/FrameTools.cpp index da34972d94..ea6f504e7c 100644 --- a/Source/Core/DolphinWX/FrameTools.cpp +++ b/Source/Core/DolphinWX/FrameTools.cpp @@ -1204,7 +1204,7 @@ void CFrame::OnLoadGameCubeIPLEUR(wxCommandEvent&) void CFrame::OnExportAllSaves(wxCommandEvent& WXUNUSED(event)) { - WiiSave::ExportAll(); + WiiSave::ExportAll(File::GetUserPath(D_USER_IDX)); } void CFrame::OnImportSave(wxCommandEvent& WXUNUSED(event)) diff --git a/Source/Core/DolphinWX/GameListCtrl.cpp b/Source/Core/DolphinWX/GameListCtrl.cpp index d0d9dfeeac..fcf0aa3d0f 100644 --- a/Source/Core/DolphinWX/GameListCtrl.cpp +++ b/Source/Core/DolphinWX/GameListCtrl.cpp @@ -988,7 +988,7 @@ void GameListCtrl::OnExportSave(wxCommandEvent& WXUNUSED(event)) { const UICommon::GameFile* iso = GetSelectedISO(); if (iso) - WiiSave::Export(iso->GetTitleID()); + WiiSave::Export(iso->GetTitleID(), File::GetUserPath(D_USER_IDX)); } // Save this file as the default file