diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt
index 0c8ed8946a..c9704450ab 100644
--- a/Source/Core/Core/CMakeLists.txt
+++ b/Source/Core/Core/CMakeLists.txt
@@ -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
diff --git a/Source/Core/Core/Core.vcxproj b/Source/Core/Core/Core.vcxproj
index 549bc38c35..86edd95d87 100644
--- a/Source/Core/Core/Core.vcxproj
+++ b/Source/Core/Core/Core.vcxproj
@@ -177,6 +177,7 @@
+
@@ -427,6 +428,7 @@
+
diff --git a/Source/Core/Core/Core.vcxproj.filters b/Source/Core/Core/Core.vcxproj.filters
index 1d5792cc33..18bce72497 100644
--- a/Source/Core/Core/Core.vcxproj.filters
+++ b/Source/Core/Core/Core.vcxproj.filters
@@ -759,6 +759,9 @@
IOS\ES
+
+ IOS\ES
+
IOS\ES
@@ -1370,6 +1373,9 @@
IOS\ES
+
+ IOS\ES
+
IOS\FS
diff --git a/Source/Core/Core/IOS/ES/NandUtils.cpp b/Source/Core/Core/IOS/ES/NandUtils.cpp
new file mode 100644
index 0000000000..15a313c94d
--- /dev/null
+++ b/Source/Core/Core/IOS/ES/NandUtils.cpp
@@ -0,0 +1,114 @@
+// Copyright 2017 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#include
+#include
+#include
+#include
+
+#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 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 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(type) << 32 | identifier);
+ }
+ }
+
+ return title_ids;
+}
+
+std::vector GetInstalledTitles()
+{
+ return GetTitlesInTitleOrImport(Common::RootUserPath(Common::FROM_SESSION_ROOT) + "/title");
+}
+
+std::vector GetTitleImports()
+{
+ return GetTitlesInTitleOrImport(Common::RootUserPath(Common::FROM_SESSION_ROOT) + "/import");
+}
+
+std::vector 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 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(type) << 32 | identifier);
+ }
+ }
+
+ return title_ids;
+}
+} // namespace ES
+} // namespace IOS
diff --git a/Source/Core/Core/IOS/ES/NandUtils.h b/Source/Core/Core/IOS/ES/NandUtils.h
new file mode 100644
index 0000000000..0cd9363290
--- /dev/null
+++ b/Source/Core/Core/IOS/ES/NandUtils.h
@@ -0,0 +1,23 @@
+// Copyright 2017 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include
+
+#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 GetInstalledTitles();
+// Get titles which are being imported (in /import) without checking for TMDs at all.
+std::vector GetTitleImports();
+// Get titles for which there is a ticket (in /ticket).
+std::vector GetTitlesWithTickets();
+} // namespace ES
+} // namespace IOS
diff --git a/Source/Core/Core/IOS/ES/TitleInformation.cpp b/Source/Core/Core/IOS/ES/TitleInformation.cpp
index dea38aa386..47f0870973 100644
--- a/Source/Core/Core/IOS/ES/TitleInformation.cpp
+++ b/Source/Core/Core/IOS/ES/TitleInformation.cpp
@@ -5,7 +5,6 @@
#include "Core/IOS/ES/ES.h"
#include
-#include
#include
#include
#include
@@ -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 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 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(type) << 32 | identifier);
- }
- }
-
- return title_ids;
-}
-
-// Returns a vector of title IDs for which there is a ticket.
-static std::vector 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 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(type) << 32 | identifier);
- }
- }
-
- return title_ids;
-}
-
IPCCommandResult ES::GetTitleCount(const std::vector& 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& titles, const IOCtlVReque
IPCCommandResult ES::GetTitleCount(const IOCtlVRequest& request)
{
- const std::vector titles = GetInstalledTitles();
+ const std::vector 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 titles = GetTitlesWithTickets();
+ const std::vector 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)
diff --git a/Source/Core/DiscIO/NANDContentLoader.h b/Source/Core/DiscIO/NANDContentLoader.h
index edeea6431a..5b428bf5b4 100644
--- a/Source/Core/DiscIO/NANDContentLoader.h
+++ b/Source/Core/DiscIO/NANDContentLoader.h
@@ -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);