Large diffs are not rendered by default.

@@ -0,0 +1,135 @@
// Copyright 2010 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

#pragma once

#include <array>
#include <mbedtls/aes.h>
#include <string>
#include <utility>
#include <vector>

#include "Common/CommonTypes.h"
#include "Common/Swap.h"

class WiiSave
{
public:
/// Import a save into the NAND from a .bin file.
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, std::string export_path);
~WiiSave();

bool Import();
bool Export();

void ReadHDR();
void ReadBKHDR();
void WriteHDR();
void WriteBKHDR();
void ImportWiiSaveFiles();
void ExportWiiSaveFiles();
void do_sig();
void make_ec_cert(u8* cert, const u8* sig, const char* signer, const char* name, const u8* priv,
const u32 key_id);
bool getPaths(bool for_export = false);
void ScanForFiles(const std::string& save_directory, std::vector<std::string>& file_list,
u32* num_files, u32* size_files);

mbedtls_aes_context m_aes_ctx;
std::array<u8, 0x10> m_sd_iv;
std::vector<std::string> m_files_list;

std::string m_encrypted_save_path;

std::string m_wii_title_path;

std::array<u8, 0x10> m_iv;

u64 m_title_id;

bool m_valid;

enum
{
BLOCK_SZ = 0x40,
HDR_SZ = 0x20,
ICON_SZ = 0x1200,
BNR_SZ = 0x60a0,
FULL_BNR_MIN = 0x72a0, // BNR_SZ + 1*ICON_SZ
FULL_BNR_MAX = 0xF0A0, // BNR_SZ + 8*ICON_SZ
HEADER_SZ = 0xF0C0, // HDR_SZ + FULL_BNR_MAX
BK_LISTED_SZ = 0x70, // Size before rounding to nearest block
BK_SZ = 0x80,
FILE_HDR_SZ = 0x80,

SIG_SZ = 0x40,
NG_CERT_SZ = 0x180,
AP_CERT_SZ = 0x180,
FULL_CERT_SZ = 0x3C0, // SIG_SZ + NG_CERT_SZ + AP_CERT_SZ + 0x80?

BK_HDR_MAGIC = 0x426B0001,
FILE_HDR_MAGIC = 0x03adf17e
};

#pragma pack(push, 1)

struct DataBinHeader // encrypted
{
Common::BigEndianValue<u64> save_game_title;
Common::BigEndianValue<u32> banner_size; // (0x72A0 or 0xF0A0, also seen 0xBAA0)
u8 permissions;
u8 unk1; // maybe permissions is a be16
std::array<u8, 0x10> md5; // md5 of plaintext header with md5 blanker applied
Common::BigEndianValue<u16> unk2;
};

struct Header
{
DataBinHeader hdr;
u8 banner[FULL_BNR_MAX];
};

struct BkHeader // Not encrypted
{
Common::BigEndianValue<u32> size; // 0x00000070
// u16 magic; // 'Bk'
// u16 magic2; // or version (0x0001)
Common::BigEndianValue<u32> magic; // 0x426B0001
Common::BigEndianValue<u32> ngid;
Common::BigEndianValue<u32> number_of_files;
Common::BigEndianValue<u32> size_of_files;
Common::BigEndianValue<u32> unk1;
Common::BigEndianValue<u32> unk2;
Common::BigEndianValue<u32> total_size;
std::array<u8, 64> unk3;
Common::BigEndianValue<u64> save_game_title;
std::array<u8, 6> mac_address;
std::array<u8, 0x12> padding;
};

struct FileHDR // encrypted
{
Common::BigEndianValue<u32> magic; // 0x03adf17e
Common::BigEndianValue<u32> size;
u8 permissions;
u8 attrib;
u8 type; // (1=file, 2=directory)
std::array<char, 0x45> name;
std::array<u8, 0x10> iv;
std::array<u8, 0x20> unk;
};
#pragma pack(pop)

Header m_header;
Header m_encrypted_header;
BkHeader m_bk_hdr;
};

This file was deleted.

@@ -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"
@@ -258,14 +258,16 @@ void GameList::OpenProperties()

void GameList::ExportWiiSave()
{
QMessageBox result_dialog(this);

const bool success = CWiiSaveCrypted::ExportWiiSave(GetSelectedGame()->GetTitleID());
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;

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.exec();
if (WiiSave::Export(GetSelectedGame()->GetTitleID(), export_dir.toStdString()))
QMessageBox::information(this, tr("Save Export"), tr("Successfully exported save files"));
else
QMessageBox::critical(this, tr("Save Export"), tr("Failed to export save files."));
}

void GameList::OpenWiki()
@@ -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"
@@ -896,13 +896,26 @@ void MenuBar::ImportWiiSave()
tr("Wii save files (*.bin);;"
"All Files (*)"));

if (!file.isEmpty())
CWiiSaveCrypted::ImportWiiSave(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()
{
CWiiSaveCrypted::ExportAllSaves();
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)", "", static_cast<int>(count)));
}

void MenuBar::CheckNAND()
@@ -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::ExportAll(File::GetUserPath(D_USER_IDX));
}

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::Import(WxStrToStr(path));
}

void CFrame::OnShowCheatsWindow(wxCommandEvent& WXUNUSED(event))
@@ -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::Export(iso->GetTitleID(), File::GetUserPath(D_USER_IDX));
}

// Save this file as the default file