WiiSave: Refactor import/export code

The current WiiSave code is extremely messy, as it exposes all kinds of
implementation details in the header (including internal struct
definitions and magic numbers that don't have to be).

The read/write code is intermingled, so it's hard to tell which members
are used, or when/where they are set at all.

It also implicitly relies on some functions being called in a specific
order since it doesn't seek manually every time, which makes the code
even more fragile.

The logic is also hardcoded to only support bin->nand or nand->bin,
even though it would be useful to support nand->nand (for the
Movie save copying code, for example).

This commit attempts to solve these problems by getting rid of the
WiiSave class:

* Read/write code is moved to new Storage classes (NandStorage and
  DataBinStorage) with small, clear functions that do one and only
  one thing.

* The import/export logic was refactored into a generic Copy function
  that takes two storages as parameters.

* The existing import and export functions are now just small wrappers
  that call Copy with the appropriate storages.
This commit is contained in:
Léo Lam 2018-05-27 01:59:23 +02:00
parent dd77ace56a
commit a46a8dd378
2 changed files with 522 additions and 630 deletions

File diff suppressed because it is too large Load Diff

View File

@ -4,138 +4,42 @@
#pragma once
#include <array>
#include <cstddef>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "Common/CommonTypes.h"
#include "Common/Swap.h"
namespace IOS
{
namespace HLE
{
class Kernel;
namespace FS
{
class FileSystem;
}
class IOSC;
}
} // namespace IOS::HLE
class WiiSave
namespace 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:
WiiSave(IOS::HLE::Kernel& ios, std::string filename);
WiiSave(IOS::HLE::Kernel& ios, 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();
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);
IOS::HLE::Kernel& m_ios;
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;
class Storage;
struct StorageDeleter
{
void operator()(Storage* p) const;
};
using StoragePointer = std::unique_ptr<Storage, StorageDeleter>;
StoragePointer MakeNandStorage(IOS::HLE::FS::FileSystem* fs, u64 tid);
StoragePointer MakeDataBinStorage(IOS::HLE::IOSC* iosc, const std::string& path, const char* mode);
bool Copy(Storage* source, Storage* destination);
/// Import a save into the NAND from a .bin file.
bool Import(const std::string& data_bin_path);
/// Export a save to a .bin file.
bool Export(u64 tid, const std::string& export_path);
/// Export all saves that are in the NAND. Returns the number of exported saves.
size_t ExportAll(const std::string& export_path);
} // namespace WiiSave