WiiUtils: Add utility functions to handle prep-work for importing 'SD-card export' style Wii saves.

This commit is contained in:
Admiral H. Curtiss 2020-12-31 18:51:34 +01:00
parent 7abe1085e3
commit 46e4c17db3
2 changed files with 86 additions and 0 deletions

View File

@ -19,6 +19,7 @@
#include <fmt/format.h>
#include <pugixml.hpp>
#include "Common/Align.h"
#include "Common/Assert.h"
#include "Common/CommonTypes.h"
#include "Common/FileUtil.h"
@ -223,6 +224,67 @@ bool IsTitleInstalled(u64 title_id)
[](const std::string& file) { return file != "title.tmd"; });
}
bool IsTMDImported(IOS::HLE::FS::FileSystem& fs, u64 title_id)
{
const auto entries = fs.ReadDirectory(0, 0, Common::GetTitleContentPath(title_id));
return entries && std::any_of(entries->begin(), entries->end(),
[](const std::string& file) { return file == "title.tmd"; });
}
IOS::ES::TMDReader FindBackupTMD(IOS::HLE::FS::FileSystem& fs, u64 title_id)
{
auto file = fs.OpenFile(IOS::PID_KERNEL, IOS::PID_KERNEL,
"/title/00000001/00000002/data/tmds.sys", IOS::HLE::FS::Mode::Read);
if (!file)
return {};
// structure of this file is as follows:
// - 32 bytes descriptor of a TMD, which contains a title ID and a length
// - the TMD, with padding aligning to 32 bytes
// - repeat for as many TMDs as stored
while (true)
{
std::array<u8, 32> descriptor;
if (!file->Read(descriptor.data(), descriptor.size()))
return {};
const u64 tid = Common::swap64(descriptor.data());
const u32 tmd_length = Common::swap32(descriptor.data() + 8);
if (tid == title_id)
{
// found the right TMD
std::vector<u8> tmd_bytes(tmd_length);
if (!file->Read(tmd_bytes.data(), tmd_length))
return {};
return IOS::ES::TMDReader(std::move(tmd_bytes));
}
// not the right TMD, skip this one and go to the next
if (!file->Seek(Common::AlignUp(tmd_length, 32), IOS::HLE::FS::SeekMode::Current))
return {};
}
}
bool EnsureTMDIsImported(IOS::HLE::FS::FileSystem& fs, IOS::HLE::Device::ES& es, u64 title_id)
{
if (IsTMDImported(fs, title_id))
return true;
auto tmd = FindBackupTMD(fs, title_id);
if (!tmd.IsValid())
return false;
IOS::HLE::Device::ES::Context context;
context.uid = IOS::SYSMENU_UID;
context.gid = IOS::SYSMENU_GID;
const auto import_result =
es.ImportTmd(context, tmd.GetBytes(), Titles::SYSTEM_MENU, IOS::ES::TITLE_TYPE_DEFAULT);
if (import_result != IOS::HLE::IPC_SUCCESS)
return false;
return es.ImportTitleDone(context) == IOS::HLE::IPC_SUCCESS;
}
// Common functionality for system updaters.
class SystemUpdater
{

View File

@ -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,