IOS: Add NandUtils
This keeps the ES specific NAND code in a single place and makes it reusable. Eventually, other ES specific code will be moved to it.
This commit is contained in:
parent
9604a06921
commit
194b0ae36d
|
@ -150,6 +150,7 @@ set(SRCS
|
|||
IOS/ES/ES.cpp
|
||||
IOS/ES/Formats.cpp
|
||||
IOS/ES/Identity.cpp
|
||||
IOS/ES/NandUtils.cpp
|
||||
IOS/ES/TitleContents.cpp
|
||||
IOS/ES/TitleInformation.cpp
|
||||
IOS/ES/TitleManagement.cpp
|
||||
|
|
|
@ -177,6 +177,7 @@
|
|||
<ClCompile Include="IOS\ES\ES.cpp" />
|
||||
<ClCompile Include="IOS\ES\Formats.cpp" />
|
||||
<ClCompile Include="IOS\ES\Identity.cpp" />
|
||||
<ClCompile Include="IOS\ES\NandUtils.cpp" />
|
||||
<ClCompile Include="IOS\ES\TitleContents.cpp" />
|
||||
<ClCompile Include="IOS\ES\TitleInformation.cpp" />
|
||||
<ClCompile Include="IOS\ES\TitleManagement.cpp" />
|
||||
|
@ -427,6 +428,7 @@
|
|||
<ClInclude Include="IOS\DI\DI.h" />
|
||||
<ClInclude Include="IOS\ES\ES.h" />
|
||||
<ClInclude Include="IOS\ES\Formats.h" />
|
||||
<ClInclude Include="IOS\ES\NandUtils.h" />
|
||||
<ClInclude Include="IOS\FS\FileIO.h" />
|
||||
<ClInclude Include="IOS\FS\FS.h" />
|
||||
<ClInclude Include="IOS\Network\ICMPLin.h" />
|
||||
|
|
|
@ -759,6 +759,9 @@
|
|||
<ClCompile Include="IOS\ES\Identity.cpp">
|
||||
<Filter>IOS\ES</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="IOS\ES\NandUtils.cpp">
|
||||
<Filter>IOS\ES</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="IOS\ES\TitleContents.cpp">
|
||||
<Filter>IOS\ES</Filter>
|
||||
</ClCompile>
|
||||
|
@ -1370,6 +1373,9 @@
|
|||
<ClInclude Include="IOS\ES\ES.h">
|
||||
<Filter>IOS\ES</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IOS\ES\NandUtils.h">
|
||||
<Filter>IOS\ES</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IOS\FS\FileIO.h">
|
||||
<Filter>IOS\FS</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
// Copyright 2017 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Common/NandPaths.h"
|
||||
#include "Core/IOS/ES/Formats.h"
|
||||
#include "Core/IOS/ES/NandUtils.h"
|
||||
|
||||
namespace IOS
|
||||
{
|
||||
namespace ES
|
||||
{
|
||||
static bool IsValidPartOfTitleID(const std::string& string)
|
||||
{
|
||||
if (string.length() != 8)
|
||||
return false;
|
||||
return std::all_of(string.begin(), string.end(),
|
||||
[](const auto character) { return std::isxdigit(character) != 0; });
|
||||
}
|
||||
|
||||
static std::vector<u64> GetTitlesInTitleOrImport(const std::string& titles_dir)
|
||||
{
|
||||
if (!File::IsDirectory(titles_dir))
|
||||
{
|
||||
ERROR_LOG(IOS_ES, "%s is not a directory", titles_dir.c_str());
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<u64> title_ids;
|
||||
|
||||
// The /title and /import directories contain one directory per title type, and each of them has
|
||||
// a directory per title (where the name is the low 32 bits of the title ID in %08x format).
|
||||
const auto entries = File::ScanDirectoryTree(titles_dir, true);
|
||||
for (const File::FSTEntry& title_type : entries.children)
|
||||
{
|
||||
if (!title_type.isDirectory || !IsValidPartOfTitleID(title_type.virtualName))
|
||||
continue;
|
||||
|
||||
if (title_type.children.empty())
|
||||
continue;
|
||||
|
||||
for (const File::FSTEntry& title_identifier : title_type.children)
|
||||
{
|
||||
if (!title_identifier.isDirectory || !IsValidPartOfTitleID(title_identifier.virtualName))
|
||||
continue;
|
||||
|
||||
const u32 type = std::stoul(title_type.virtualName, nullptr, 16);
|
||||
const u32 identifier = std::stoul(title_identifier.virtualName, nullptr, 16);
|
||||
title_ids.push_back(static_cast<u64>(type) << 32 | identifier);
|
||||
}
|
||||
}
|
||||
|
||||
return title_ids;
|
||||
}
|
||||
|
||||
std::vector<u64> GetInstalledTitles()
|
||||
{
|
||||
return GetTitlesInTitleOrImport(Common::RootUserPath(Common::FROM_SESSION_ROOT) + "/title");
|
||||
}
|
||||
|
||||
std::vector<u64> GetTitleImports()
|
||||
{
|
||||
return GetTitlesInTitleOrImport(Common::RootUserPath(Common::FROM_SESSION_ROOT) + "/import");
|
||||
}
|
||||
|
||||
std::vector<u64> GetTitlesWithTickets()
|
||||
{
|
||||
const std::string tickets_dir = Common::RootUserPath(Common::FROM_SESSION_ROOT) + "/ticket";
|
||||
if (!File::IsDirectory(tickets_dir))
|
||||
{
|
||||
ERROR_LOG(IOS_ES, "/ticket is not a directory");
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<u64> title_ids;
|
||||
|
||||
// The /ticket directory contains one directory per title type, and each of them contains
|
||||
// one ticket per title (where the name is the low 32 bits of the title ID in %08x format).
|
||||
const auto entries = File::ScanDirectoryTree(tickets_dir, true);
|
||||
for (const File::FSTEntry& title_type : entries.children)
|
||||
{
|
||||
if (!title_type.isDirectory || !IsValidPartOfTitleID(title_type.virtualName))
|
||||
continue;
|
||||
|
||||
if (title_type.children.empty())
|
||||
continue;
|
||||
|
||||
for (const File::FSTEntry& ticket : title_type.children)
|
||||
{
|
||||
const std::string name_without_ext = ticket.virtualName.substr(0, 8);
|
||||
if (ticket.isDirectory || !IsValidPartOfTitleID(name_without_ext) ||
|
||||
name_without_ext + ".tik" != ticket.virtualName)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const u32 type = std::stoul(title_type.virtualName, nullptr, 16);
|
||||
const u32 identifier = std::stoul(name_without_ext, nullptr, 16);
|
||||
title_ids.push_back(static_cast<u64>(type) << 32 | identifier);
|
||||
}
|
||||
}
|
||||
|
||||
return title_ids;
|
||||
}
|
||||
} // namespace ES
|
||||
} // namespace IOS
|
|
@ -0,0 +1,23 @@
|
|||
// Copyright 2017 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Core/IOS/ES/Formats.h"
|
||||
|
||||
namespace IOS
|
||||
{
|
||||
namespace ES
|
||||
{
|
||||
// Get installed titles (in /title) without checking for TMDs at all.
|
||||
std::vector<u64> GetInstalledTitles();
|
||||
// Get titles which are being imported (in /import) without checking for TMDs at all.
|
||||
std::vector<u64> GetTitleImports();
|
||||
// Get titles for which there is a ticket (in /ticket).
|
||||
std::vector<u64> GetTitlesWithTickets();
|
||||
} // namespace ES
|
||||
} // namespace IOS
|
|
@ -5,7 +5,6 @@
|
|||
#include "Core/IOS/ES/ES.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cinttypes>
|
||||
#include <cstdio>
|
||||
#include <iterator>
|
||||
|
@ -18,6 +17,7 @@
|
|||
#include "Common/StringUtil.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
#include "Core/IOS/ES/Formats.h"
|
||||
#include "Core/IOS/ES/NandUtils.h"
|
||||
#include "DiscIO/NANDContentLoader.h"
|
||||
|
||||
namespace IOS
|
||||
|
@ -132,92 +132,6 @@ IPCCommandResult ES::GetTMDStoredContents(const IOCtlVRequest& request)
|
|||
return GetStoredContents(IOS::ES::TMDReader{std::move(tmd_bytes)}, request);
|
||||
}
|
||||
|
||||
static bool IsValidPartOfTitleID(const std::string& string)
|
||||
{
|
||||
if (string.length() != 8)
|
||||
return false;
|
||||
return std::all_of(string.begin(), string.end(),
|
||||
[](const auto character) { return std::isxdigit(character) != 0; });
|
||||
}
|
||||
|
||||
// Returns a vector of title IDs. IOS does not check the TMD at all here.
|
||||
static std::vector<u64> GetInstalledTitles()
|
||||
{
|
||||
const std::string titles_dir = Common::RootUserPath(Common::FROM_SESSION_ROOT) + "/title";
|
||||
if (!File::IsDirectory(titles_dir))
|
||||
{
|
||||
ERROR_LOG(IOS_ES, "/title is not a directory");
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<u64> title_ids;
|
||||
|
||||
// The /title directory contains one directory per title type, and each of them contains
|
||||
// a directory per title (where the name is the low 32 bits of the title ID in %08x format).
|
||||
const auto entries = File::ScanDirectoryTree(titles_dir, true);
|
||||
for (const File::FSTEntry& title_type : entries.children)
|
||||
{
|
||||
if (!title_type.isDirectory || !IsValidPartOfTitleID(title_type.virtualName))
|
||||
continue;
|
||||
|
||||
if (title_type.children.empty())
|
||||
continue;
|
||||
|
||||
for (const File::FSTEntry& title_identifier : title_type.children)
|
||||
{
|
||||
if (!title_identifier.isDirectory || !IsValidPartOfTitleID(title_identifier.virtualName))
|
||||
continue;
|
||||
|
||||
const u32 type = std::stoul(title_type.virtualName, nullptr, 16);
|
||||
const u32 identifier = std::stoul(title_identifier.virtualName, nullptr, 16);
|
||||
title_ids.push_back(static_cast<u64>(type) << 32 | identifier);
|
||||
}
|
||||
}
|
||||
|
||||
return title_ids;
|
||||
}
|
||||
|
||||
// Returns a vector of title IDs for which there is a ticket.
|
||||
static std::vector<u64> GetTitlesWithTickets()
|
||||
{
|
||||
const std::string titles_dir = Common::RootUserPath(Common::FROM_SESSION_ROOT) + "/ticket";
|
||||
if (!File::IsDirectory(titles_dir))
|
||||
{
|
||||
ERROR_LOG(IOS_ES, "/ticket is not a directory");
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<u64> title_ids;
|
||||
|
||||
// The /ticket directory contains one directory per title type, and each of them contains
|
||||
// one ticket per title (where the name is the low 32 bits of the title ID in %08x format).
|
||||
const auto entries = File::ScanDirectoryTree(titles_dir, true);
|
||||
for (const File::FSTEntry& title_type : entries.children)
|
||||
{
|
||||
if (!title_type.isDirectory || !IsValidPartOfTitleID(title_type.virtualName))
|
||||
continue;
|
||||
|
||||
if (title_type.children.empty())
|
||||
continue;
|
||||
|
||||
for (const File::FSTEntry& ticket : title_type.children)
|
||||
{
|
||||
const std::string name_without_ext = ticket.virtualName.substr(0, 8);
|
||||
if (ticket.isDirectory || !IsValidPartOfTitleID(name_without_ext) ||
|
||||
name_without_ext + ".tik" != ticket.virtualName)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const u32 type = std::stoul(title_type.virtualName, nullptr, 16);
|
||||
const u32 identifier = std::stoul(name_without_ext, nullptr, 16);
|
||||
title_ids.push_back(static_cast<u64>(type) << 32 | identifier);
|
||||
}
|
||||
}
|
||||
|
||||
return title_ids;
|
||||
}
|
||||
|
||||
IPCCommandResult ES::GetTitleCount(const std::vector<u64>& titles, const IOCtlVRequest& request)
|
||||
{
|
||||
if (!request.HasNumberOfValidVectors(0, 1) || request.io_vectors[0].size != 4)
|
||||
|
@ -244,14 +158,14 @@ IPCCommandResult ES::GetTitles(const std::vector<u64>& titles, const IOCtlVReque
|
|||
|
||||
IPCCommandResult ES::GetTitleCount(const IOCtlVRequest& request)
|
||||
{
|
||||
const std::vector<u64> titles = GetInstalledTitles();
|
||||
const std::vector<u64> titles = IOS::ES::GetInstalledTitles();
|
||||
INFO_LOG(IOS_ES, "GetTitleCount: %zu titles", titles.size());
|
||||
return GetTitleCount(titles, request);
|
||||
}
|
||||
|
||||
IPCCommandResult ES::GetTitles(const IOCtlVRequest& request)
|
||||
{
|
||||
return GetTitles(GetInstalledTitles(), request);
|
||||
return GetTitles(IOS::ES::GetInstalledTitles(), request);
|
||||
}
|
||||
|
||||
IPCCommandResult ES::GetStoredTMDSize(const IOCtlVRequest& request)
|
||||
|
@ -300,14 +214,14 @@ IPCCommandResult ES::GetStoredTMD(const IOCtlVRequest& request)
|
|||
|
||||
IPCCommandResult ES::GetOwnedTitleCount(const IOCtlVRequest& request)
|
||||
{
|
||||
const std::vector<u64> titles = GetTitlesWithTickets();
|
||||
const std::vector<u64> titles = IOS::ES::GetTitlesWithTickets();
|
||||
INFO_LOG(IOS_ES, "GetOwnedTitleCount: %zu titles", titles.size());
|
||||
return GetTitleCount(titles, request);
|
||||
}
|
||||
|
||||
IPCCommandResult ES::GetOwnedTitles(const IOCtlVRequest& request)
|
||||
{
|
||||
return GetTitles(GetTitlesWithTickets(), request);
|
||||
return GetTitles(IOS::ES::GetTitlesWithTickets(), request);
|
||||
}
|
||||
|
||||
IPCCommandResult ES::GetBoot2Version(const IOCtlVRequest& request)
|
||||
|
|
|
@ -23,6 +23,7 @@ namespace DiscIO
|
|||
{
|
||||
enum class Region;
|
||||
|
||||
// TODO: move some of these to Core/IOS/ES.
|
||||
bool AddTicket(const IOS::ES::TicketReader& signed_ticket);
|
||||
IOS::ES::TicketReader FindSignedTicket(u64 title_id);
|
||||
|
||||
|
|
Loading…
Reference in New Issue