@@ -6,10 +6,12 @@

#include <cstddef>
#include <functional>
#include <optional>
#include <string>
#include <unordered_set>

#include "Common/CommonTypes.h"
#include "Core/IOS/ES/Formats.h"

// Small utility functions for common Wii related tasks.

@@ -23,6 +25,16 @@ namespace IOS::HLE
class Kernel;
}

namespace IOS::HLE::FS
{
class FileSystem;
}

namespace IOS::HLE::Device
{
class ES;
}

namespace WiiUtils
{
enum class InstallType
@@ -40,6 +52,18 @@ bool UninstallTitle(u64 title_id);

bool IsTitleInstalled(u64 title_id);

// Checks if there's a title.tmd imported for the given title ID.
bool IsTMDImported(IOS::HLE::FS::FileSystem& fs, u64 title_id);

// Searches for a TMD matching the given title ID in /title/00000001/00000002/data/tmds.sys.
// Returns it if it exists, otherwise returns an empty invalid TMD.
IOS::ES::TMDReader FindBackupTMD(IOS::HLE::FS::FileSystem& fs, u64 title_id);

// Checks if there's a title.tmd imported for the given title ID. If there is not, we attempt to
// re-import it from the TMDs stored in /title/00000001/00000002/data/tmds.sys.
// Returns true if, after this function call, we have an imported title.tmd, or false if not.
bool EnsureTMDIsImported(IOS::HLE::FS::FileSystem& fs, IOS::HLE::Device::ES& es, u64 title_id);

enum class UpdateResult
{
Succeeded,
@@ -452,8 +452,11 @@ void GameList::ExportWiiSave()
QList<std::string> failed;
for (const auto& game : GetSelectedGames())
{
if (!WiiSave::Export(game->GetTitleID(), export_dir.toStdString()))
if (WiiSave::Export(game->GetTitleID(), export_dir.toStdString()) !=
WiiSave::CopyResult::Success)
{
failed.push_back(game->GetName(UICommon::GameFile::Variant::LongAndPossiblyCustom));
}
}

if (!failed.isEmpty())
@@ -1066,19 +1066,39 @@ void MenuBar::ImportWiiSave()
if (file.isEmpty())
return;

bool cancelled = false;
auto can_overwrite = [&] {
bool yes = ModalMessageBox::question(
this, tr("Save Import"),
tr("Save data for this title already exists in the NAND. Consider backing up "
"the current data before overwriting.\nOverwrite now?")) == QMessageBox::Yes;
cancelled = !yes;
return yes;
return ModalMessageBox::question(
this, tr("Save Import"),
tr("Save data for this title already exists in the NAND. Consider backing up "
"the current data before overwriting.\nOverwrite now?")) == QMessageBox::Yes;
};
if (WiiSave::Import(file.toStdString(), can_overwrite))
ModalMessageBox::information(this, tr("Save Import"), tr("Successfully imported save files."));
else if (!cancelled)
ModalMessageBox::critical(this, tr("Save Import"), tr("Failed to import save files."));

const auto result = WiiSave::Import(file.toStdString(), can_overwrite);
switch (result)
{
case WiiSave::CopyResult::Success:
ModalMessageBox::information(this, tr("Save Import"), tr("Successfully imported save file."));
break;
case WiiSave::CopyResult::CorruptedSource:
ModalMessageBox::critical(this, tr("Save Import"),
tr("Failed to import save file. The given file appears to be "
"corrupted or is not a valid Wii save."));
break;
case WiiSave::CopyResult::TitleMissing:
ModalMessageBox::critical(
this, tr("Save Import"),
tr("Failed to import save file. Please launch the game once, then try again."));
break;
case WiiSave::CopyResult::Cancelled:
break;
default:
ModalMessageBox::critical(
this, tr("Save Import"),
tr("Failed to import save file. Your NAND may be corrupt, or something is preventing "
"access to files within it. Try repairing your NAND (Tools -> Manage NAND -> Check "
"NAND...), then import the save again."));
break;
}
}

void MenuBar::ExportWiiSaves()