diff --git a/Source/Core/DolphinWX/DolphinWX.vcproj b/Source/Core/DolphinWX/DolphinWX.vcproj
index fa39cb8e9f..0af4eef3e1 100644
--- a/Source/Core/DolphinWX/DolphinWX.vcproj
+++ b/Source/Core/DolphinWX/DolphinWX.vcproj
@@ -1097,46 +1097,6 @@
RelativePath=".\src\GameListCtrl.h"
>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -1505,6 +1465,58 @@
>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Append(IDM_LUA, _T("New &Lua Console"));
- toolsMenu->Append(IDM_MEMCARD, _T("&Memcard Manager"));
+ toolsMenu->Append(IDM_MEMCARD, _T("&Memcard Manager (GC)"));
+ toolsMenu->Append(IDM_IMPORTSAVE, _T("Wii Save Import (experimental)"));
toolsMenu->Append(IDM_CHEATS, _T("Action &Replay Manager"));
#if defined(HAVE_SFML) && HAVE_SFML
@@ -782,10 +784,30 @@ void CFrame::OnNetPlay(wxCommandEvent& WXUNUSED (event))
void CFrame::OnMemcard(wxCommandEvent& WXUNUSED (event))
{
-m_bModalDialogOpen = true;
+ m_bModalDialogOpen = true;
CMemcardManager MemcardManager(this);
MemcardManager.ShowModal();
-m_bModalDialogOpen = false;
+ m_bModalDialogOpen = false;
+}
+
+void CFrame::OnImportSave(wxCommandEvent& WXUNUSED (event))
+{
+ wxString path = wxFileSelector(_T("Select the save file"),
+ wxEmptyString, wxEmptyString, wxEmptyString,
+ wxString::Format
+ (
+ _T("Wii save files|data.bin|All files (%s)|%s"),
+ wxFileSelectorDefaultWildcardStr,
+ wxFileSelectorDefaultWildcardStr
+ ),
+ wxFD_OPEN | wxFD_PREVIEW | wxFD_FILE_MUST_EXIST,
+ this);
+
+ if (!path.IsEmpty())
+ {
+ CWiiSaveCrypted saveFile(path.ToUTF8().data());
+ saveFile.Extract();
+ }
}
void CFrame::OnOpenLuaWindow(wxCommandEvent& WXUNUSED (event))
diff --git a/Source/Core/DolphinWX/Src/Globals.h b/Source/Core/DolphinWX/Src/Globals.h
index 43341230b0..8f107b25aa 100644
--- a/Source/Core/DolphinWX/Src/Globals.h
+++ b/Source/Core/DolphinWX/Src/Globals.h
@@ -219,6 +219,7 @@ enum
IDM_NOTIFYMAPLOADED,
IDM_OPENCONTAININGFOLDER,
IDM_OPENSAVEFOLDER,
+ IDM_IMPORTSAVE,
IDM_SETDEFAULTGCM,
IDM_DELETEGCM,
IDM_COMPRESSGCM,
diff --git a/Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.cpp b/Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.cpp
new file mode 100644
index 0000000000..f82bb49155
--- /dev/null
+++ b/Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.cpp
@@ -0,0 +1,225 @@
+// Copyright (C) 2003 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+// Based off of tachtig http://git.infradead.org/?p=users/segher/wii.git
+
+#include "stdafx.h"
+
+#include "WiiSaveCrypted.h"
+#include "FileUtil.h"
+
+u8 SD_IV[0x10] = {0x21, 0x67, 0x12, 0xE6, 0xAA, 0x1F, 0x68, 0x9F,
+ 0x95, 0xC5, 0xA2, 0x23, 0x24, 0xDC, 0x6A, 0x98};
+
+CWiiSaveCrypted::CWiiSaveCrypted(const char* FileName)
+{
+ _filename = std::string(FileName);
+
+ const u8 SDKey[16] = {0xAB, 0x01, 0xB9, 0xD8, 0xE1, 0x62, 0x2B, 0x08,
+ 0xAF, 0xBA, 0xD8, 0x4D, 0xBF, 0xC2, 0xA5, 0x5D};
+ AES_set_decrypt_key(SDKey, 128, &m_AES_KEY);
+ b_valid = true;
+ ReadHDR();
+ ReadBKHDR();
+}
+
+void CWiiSaveCrypted::ReadHDR()
+{
+ saveFileP = fopen(_filename.c_str(), "rb");
+ if (!saveFileP)
+ {
+ PanicAlert("Cannot open %s", _filename.c_str());
+ b_valid = false;
+ return;
+ }
+ Data_Bin_HDR * tmpHDR = new Data_Bin_HDR;
+
+ if (fread(tmpHDR, HDR_SZ, 1, saveFileP) != 1)
+ {
+ PanicAlert("failed to read header");
+ b_valid = false;
+ return;
+ }
+ AES_cbc_encrypt((const u8*)tmpHDR, (u8*)&hdr, HDR_SZ, &m_AES_KEY, SD_IV, AES_DECRYPT);
+ delete tmpHDR;
+ _bannerSize = Common::swap32(hdr.BannerSize);
+ if ((_bannerSize < FULL_BNR_MIN) || (_bannerSize > FULL_BNR_MAX) ||
+ (((_bannerSize - BNR_SZ) % ICON_SZ) != 0))
+ {
+ PanicAlert("not a wii save or read failure for file header size %x", _bannerSize);
+ b_valid = false;
+ return;
+ }
+ _saveGameTitle = Common::swap64(hdr.SaveGameTitle);
+ fclose(saveFileP);
+}
+void CWiiSaveCrypted::ReadBKHDR()
+{
+ if (!b_valid) return;
+ saveFileP = fopen(_filename.c_str(), "rb");
+ if (!saveFileP)
+ {
+ PanicAlert("Cannot open %s", _filename.c_str());
+ b_valid = false;
+ return;
+ }
+ fseek(saveFileP, HDR_SZ + FULL_BNR_MAX/*_bannerSize*/, SEEK_SET);
+
+ if (fread(&bkhdr, BK_SZ, 1, saveFileP) != 1)
+ {
+ PanicAlert("failed to read bk header");
+ b_valid = false;
+ return;
+ }
+
+ if (Common::swap64((u8*)&bkhdr) != 0x00000070426b0001ULL)
+ {
+ PanicAlert("Invalid Size or Magic word %016llx", bkhdr);
+ b_valid = false;
+ return;
+ }
+ if (_saveGameTitle != Common::swap64(bkhdr.SaveGameTitle))
+ WARN_LOG(CONSOLE, "encrypted title (%x) does not match unencrypted title (%x)", _saveGameTitle, Common::swap64(bkhdr.SaveGameTitle));
+
+ _numberOfFiles = Common::swap32(bkhdr.numberOfFiles);
+ _sizeOfFiles = Common::swap32(bkhdr.sizeOfFiles);
+ _totalSize = Common::swap32(bkhdr.totalSize);
+ fclose(saveFileP);
+}
+
+void CWiiSaveCrypted::Extract()
+{
+ if (!b_valid) return;
+
+ saveFileP = fopen(_filename.c_str(), "rb");
+ if (!saveFileP)
+ {
+ PanicAlert("Cannot open %s", _filename.c_str());
+ b_valid = false;
+ return;
+ }
+
+ sprintf(dir, FULL_WII_USER_DIR "title/%08x/%08x/data/", (u32)(_saveGameTitle>>32), (u32)_saveGameTitle);
+
+ if (!PanicYesNo("Warning! it is advised to backup all files in the folder:\n%s\nDo you wish to continue?", dir))
+ return;
+
+ INFO_LOG(CONSOLE, "%s", dir);
+ File::CreateFullPath(dir);
+
+ fseek(saveFileP, HDR_SZ, SEEK_SET);
+
+ _encryptedData = new u8[_bannerSize];
+ _data = new u8[_bannerSize];
+ if (fread(_encryptedData, _bannerSize, 1, saveFileP) != 1)
+ {
+ PanicAlert("failed to read banner");
+ b_valid = false;
+ return;
+ }
+
+ AES_cbc_encrypt((const u8*)_encryptedData, (u8*)_data, _bannerSize, &m_AES_KEY, SD_IV, AES_DECRYPT);
+ delete []_encryptedData;
+
+ sprintf(path, "%sbanner.bin", dir);
+
+ // remove after code is more thoroughly tested
+ sprintf(tmpPath, "%s.bak", path);
+ File::Copy(path, tmpPath);
+ //
+
+ if (!File::Exists(path) || PanicYesNo("%s already exists, overwrite?", path))
+ {
+ INFO_LOG(CONSOLE, "creating file %s", path);
+ outFileP = fopen(path, "wb");
+ if (outFileP)
+ {
+ fwrite(_data, _bannerSize, 1, outFileP);
+ fclose(outFileP);
+ }
+ }
+ delete []_data;
+
+ int lastpos = HDR_SZ + FULL_BNR_MAX /*_bannerSize */+ BK_SZ;
+
+
+
+
+ FileHDR _tmpFileHDR;
+
+ for(u32 i = 0; i < _numberOfFiles; i++)
+ {
+ fseek(saveFileP, lastpos, SEEK_SET);
+ memset(&_tmpFileHDR, 0, FILE_HDR_SZ);
+ memset(IV, 0, 0x10);
+ u32 roundedsize;
+
+ fread(&_tmpFileHDR, FILE_HDR_SZ, 1, saveFileP);
+ lastpos += FILE_HDR_SZ;
+ if(Common::swap32(_tmpFileHDR.magic) != 0x03adf17e)
+ {
+ PanicAlert("Bad File Header");
+ break;
+ }
+ else
+ {
+ sprintf(path, "%s%s", dir, _tmpFileHDR.name);
+ if (_tmpFileHDR.type == 2)
+ {
+ PanicAlert("savegame with a dir, report me :p, %s", path);
+ // we should prolly write any future files to this new dir
+ // but tachtig doesnt do this...
+ File::CreateFullPath(path);
+ }
+ else
+ {
+ roundedsize = (Common::swap32(_tmpFileHDR.size));// + 63) & ~63; // rounding makes corrupted files for NSMBwii
+ lastpos += roundedsize;
+ _encryptedData = new u8[roundedsize];
+ _data = new u8[roundedsize];
+ fread(_encryptedData, roundedsize, 1, saveFileP);
+ memcpy(IV, _tmpFileHDR.IV, 0x10);
+ AES_cbc_encrypt((const unsigned char *)_encryptedData, _data, roundedsize, &m_AES_KEY, IV, AES_DECRYPT);
+ delete []_encryptedData;
+
+ // remove after code is more thoroughly tested
+ sprintf(tmpPath, "%s.bak", path);
+ File::Copy(path, tmpPath);
+ //
+ if (!File::Exists(path) || PanicYesNo("%s already exists, overwrite?", path))
+ {
+ INFO_LOG(CONSOLE, "creating file %s", path);
+
+ outFileP = fopen(path, "wb");
+ if (outFileP)
+ {
+ fwrite(_data, roundedsize, 1, outFileP);
+ fclose(outFileP);
+ }
+ }
+ delete []_data;
+ }
+
+ }
+ }
+fclose(saveFileP);
+}
+
+CWiiSaveCrypted::~CWiiSaveCrypted()
+{
+}
+
diff --git a/Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.h b/Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.h
new file mode 100644
index 0000000000..1fa4673428
--- /dev/null
+++ b/Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.h
@@ -0,0 +1,114 @@
+// Copyright (C) 2003 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+#ifndef _WII_SAVE_CRYPTED
+#define _WII_SAVE_CRYPTED
+
+#include "AES/aes.h"
+#include "StringUtil.h"
+
+// --- this is used for encrypted Wii save files
+
+
+
+class CWiiSaveCrypted
+{
+public:
+ CWiiSaveCrypted(const char* FileName);
+ ~CWiiSaveCrypted();
+ void ReadHDR();
+ void ReadBKHDR();
+ void Extract();
+
+private:
+ FILE *saveFileP,
+ *outFileP;
+ AES_KEY m_AES_KEY;
+
+ u8 IV[0x10],
+ *_encryptedData,
+ *_data;
+
+ char dir[1024],
+ path[1024],
+ tmpPath[1024];
+
+ u32 _bannerSize,
+ _numberOfFiles,
+ _sizeOfFiles,
+ _totalSize;
+
+ u64 _saveGameTitle;
+
+ std::string _filename;
+
+ bool b_valid;
+
+ enum
+ {
+ HDR_SZ = 0x20,
+ BK_SZ = 0x80,
+ FILE_HDR_SZ = 0x80,
+ ICON_SZ = 0x1200,
+ BNR_SZ = 0x60a0,
+ FULL_BNR_MIN = 0x72a0, // BNR_SZ + 1*ICON_SZ
+ FULL_BNR_MAX = 0xF0A0, // BNR_SZ + 8*ICON_SZ
+ };
+
+#pragma pack(push,1)
+ struct Data_Bin_HDR // encrypted
+ {
+ u64 SaveGameTitle;
+ u32 BannerSize; // (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;
+ }hdr;
+
+ struct BK_Header // Not encrypted
+ {
+ u32 size; // 0x00000070
+ u16 magic; // 'Bk'
+ u16 magic2; // or version (0x0001)
+ u32 NGid;
+ u32 numberOfFiles;
+ u32 sizeOfFiles;
+ u32 unk1;
+ u32 unk2;
+ u32 totalSize;
+ u8 unk3[64];
+ u64 SaveGameTitle;
+ u64 MACaddress;
+ u8 padding[0x10];
+ }bkhdr;
+
+ struct FileHDR // encrypted
+ {
+ u32 magic; //0x03adf17e
+ u32 size;
+ u8 Permissions;
+ u8 attrib;
+ u8 type; // (1=file, 2=directory)
+ u8 name[0x45];
+ u8 IV[0x10];
+ u8 unk[0x20];
+ };
+#pragma pack(pop)
+};
+
+#endif