Add option to configure to download system files from Nintendo Update Service (#6269)
Co-authored-by: B3n30 <benediktthomas@gmail.com>
This commit is contained in:
parent
691cb43871
commit
6bef34852c
|
@ -209,7 +209,7 @@ if (ENABLE_QT)
|
||||||
set(QT_PREFIX_HINT)
|
set(QT_PREFIX_HINT)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
find_package(Qt5 REQUIRED COMPONENTS Widgets Multimedia ${QT_PREFIX_HINT})
|
find_package(Qt5 REQUIRED COMPONENTS Widgets Multimedia Concurrent ${QT_PREFIX_HINT})
|
||||||
|
|
||||||
if (ENABLE_QT_TRANSLATION)
|
if (ENABLE_QT_TRANSLATION)
|
||||||
find_package(Qt5 REQUIRED COMPONENTS LinguistTools ${QT_PREFIX_HINT})
|
find_package(Qt5 REQUIRED COMPONENTS LinguistTools ${QT_PREFIX_HINT})
|
||||||
|
|
|
@ -266,7 +266,7 @@ endif()
|
||||||
create_target_directory_groups(citra-qt)
|
create_target_directory_groups(citra-qt)
|
||||||
|
|
||||||
target_link_libraries(citra-qt PRIVATE audio_core common core input_common network video_core)
|
target_link_libraries(citra-qt PRIVATE audio_core common core input_common network video_core)
|
||||||
target_link_libraries(citra-qt PRIVATE Boost::boost glad nihstro-headers Qt5::Widgets Qt5::Multimedia)
|
target_link_libraries(citra-qt PRIVATE Boost::boost glad nihstro-headers Qt5::Widgets Qt5::Multimedia Qt5::Concurrent)
|
||||||
target_link_libraries(citra-qt PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads)
|
target_link_libraries(citra-qt PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads)
|
||||||
|
|
||||||
target_compile_definitions(citra-qt PRIVATE
|
target_compile_definitions(citra-qt PRIVATE
|
||||||
|
|
|
@ -3,14 +3,22 @@
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <QFutureWatcher>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
#include <QProgressDialog>
|
||||||
|
#include <QtConcurrent/QtConcurrentMap>
|
||||||
#include "citra_qt/configuration/configuration_shared.h"
|
#include "citra_qt/configuration/configuration_shared.h"
|
||||||
#include "citra_qt/configuration/configure_system.h"
|
#include "citra_qt/configuration/configure_system.h"
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
|
#include "core/hle/service/am/am.h"
|
||||||
#include "core/hle/service/cfg/cfg.h"
|
#include "core/hle/service/cfg/cfg.h"
|
||||||
#include "core/hle/service/ptm/ptm.h"
|
#include "core/hle/service/ptm/ptm.h"
|
||||||
|
#include "core/hw/aes/key.h"
|
||||||
#include "ui_configure_system.h"
|
#include "ui_configure_system.h"
|
||||||
|
#ifdef ENABLE_WEB_SERVICE
|
||||||
|
#include "web_service/nus_titles.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
static const std::array<int, 12> days_in_month = {{
|
static const std::array<int, 12> days_in_month = {{
|
||||||
31,
|
31,
|
||||||
|
@ -239,6 +247,8 @@ ConfigureSystem::ConfigureSystem(QWidget* parent)
|
||||||
&ConfigureSystem::UpdateInitTime);
|
&ConfigureSystem::UpdateInitTime);
|
||||||
connect(ui->button_regenerate_console_id, &QPushButton::clicked, this,
|
connect(ui->button_regenerate_console_id, &QPushButton::clicked, this,
|
||||||
&ConfigureSystem::RefreshConsoleID);
|
&ConfigureSystem::RefreshConsoleID);
|
||||||
|
connect(ui->button_start_download, &QPushButton::clicked, this,
|
||||||
|
&ConfigureSystem::DownloadFromNUS);
|
||||||
for (u8 i = 0; i < country_names.size(); i++) {
|
for (u8 i = 0; i < country_names.size(); i++) {
|
||||||
if (std::strcmp(country_names.at(i), "") != 0) {
|
if (std::strcmp(country_names.at(i), "") != 0) {
|
||||||
ui->combo_country->addItem(tr(country_names.at(i)), i);
|
ui->combo_country->addItem(tr(country_names.at(i)), i);
|
||||||
|
@ -257,6 +267,30 @@ ConfigureSystem::ConfigureSystem(QWidget* parent)
|
||||||
ui->clock_speed_combo->setVisible(!Settings::IsConfiguringGlobal());
|
ui->clock_speed_combo->setVisible(!Settings::IsConfiguringGlobal());
|
||||||
|
|
||||||
SetupPerGameUI();
|
SetupPerGameUI();
|
||||||
|
|
||||||
|
ui->combo_download_mode->setCurrentIndex(1); // set to Recommended
|
||||||
|
bool keys_available = true;
|
||||||
|
HW::AES::InitKeys(true);
|
||||||
|
for (u8 i = 0; i < HW::AES::MaxCommonKeySlot; i++) {
|
||||||
|
HW::AES::SelectCommonKeyIndex(i);
|
||||||
|
if (!HW::AES::IsNormalKeyAvailable(HW::AES::KeySlotID::TicketCommonKey)) {
|
||||||
|
keys_available = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (keys_available) {
|
||||||
|
ui->button_start_download->setEnabled(true);
|
||||||
|
ui->combo_download_mode->setEnabled(true);
|
||||||
|
ui->label_nus_download->setText(tr("Download System Files from Nintendo servers"));
|
||||||
|
} else {
|
||||||
|
ui->button_start_download->setEnabled(false);
|
||||||
|
ui->combo_download_mode->setEnabled(false);
|
||||||
|
ui->label_nus_download->setText(
|
||||||
|
tr("Citra is missing keys to download system files. <br><a "
|
||||||
|
"href='https://citra-emu.org/wiki/aes-keys/'><span style=\"text-decoration: "
|
||||||
|
"underline; color:#039be5;\">How to get keys?</span></a>"));
|
||||||
|
}
|
||||||
|
|
||||||
ConfigureTime();
|
ConfigureTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -542,3 +576,44 @@ void ConfigureSystem::SetupPerGameUI() {
|
||||||
ConfigurationShared::SetColoredTristate(ui->toggle_new_3ds, Settings::values.is_new_3ds,
|
ConfigurationShared::SetColoredTristate(ui->toggle_new_3ds, Settings::values.is_new_3ds,
|
||||||
is_new_3ds);
|
is_new_3ds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ConfigureSystem::DownloadFromNUS() {
|
||||||
|
#ifdef ENABLE_WEB_SERVICE
|
||||||
|
ui->button_start_download->setEnabled(false);
|
||||||
|
|
||||||
|
const auto mode = static_cast<Title::Mode>(ui->combo_download_mode->currentIndex());
|
||||||
|
const std::vector<u64> titles = BuildFirmwareTitleList(mode, cfg->GetRegionValue());
|
||||||
|
|
||||||
|
QProgressDialog progress(tr("Downloading files..."), tr("Cancel"), 0,
|
||||||
|
static_cast<int>(titles.size()), this);
|
||||||
|
progress.setWindowModality(Qt::WindowModal);
|
||||||
|
|
||||||
|
QFutureWatcher<void> future_watcher;
|
||||||
|
QObject::connect(&future_watcher, &QFutureWatcher<void>::finished, &progress,
|
||||||
|
&QProgressDialog::reset);
|
||||||
|
QObject::connect(&progress, &QProgressDialog::canceled, &future_watcher,
|
||||||
|
&QFutureWatcher<void>::cancel);
|
||||||
|
QObject::connect(&future_watcher, &QFutureWatcher<void>::progressValueChanged, &progress,
|
||||||
|
&QProgressDialog::setValue);
|
||||||
|
|
||||||
|
auto failed = false;
|
||||||
|
const auto download_title = [&future_watcher, &failed](const u64& title_id) {
|
||||||
|
if (Service::AM::InstallFromNus(title_id) != Service::AM::InstallStatus::Success) {
|
||||||
|
failed = true;
|
||||||
|
future_watcher.cancel();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
future_watcher.setFuture(QtConcurrent::map(titles, download_title));
|
||||||
|
progress.exec();
|
||||||
|
future_watcher.waitForFinished();
|
||||||
|
|
||||||
|
if (failed) {
|
||||||
|
QMessageBox::critical(this, tr("Citra"), tr("Downloading system files failed."));
|
||||||
|
} else if (!future_watcher.isCanceled()) {
|
||||||
|
QMessageBox::information(this, tr("Citra"), tr("Successfully downloaded system files."));
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->button_start_download->setEnabled(true);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
|
@ -43,6 +43,8 @@ private:
|
||||||
|
|
||||||
void SetupPerGameUI();
|
void SetupPerGameUI();
|
||||||
|
|
||||||
|
void DownloadFromNUS();
|
||||||
|
|
||||||
ConfigurationShared::CheckState is_new_3ds;
|
ConfigurationShared::CheckState is_new_3ds;
|
||||||
std::unique_ptr<Ui::ConfigureSystem> ui;
|
std::unique_ptr<Ui::ConfigureSystem> ui;
|
||||||
bool enabled = false;
|
bool enabled = false;
|
||||||
|
|
|
@ -361,6 +361,52 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="15" column="0">
|
||||||
|
<widget class="QLabel" name="label_nus_download">
|
||||||
|
<property name="text">
|
||||||
|
<string>Download System Files from Nitendo servers</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="15" column="1">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_nus_download">
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="combo_download_mode">
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>All</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Recommended</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Minimal</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="button_start_download">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="layoutDirection">
|
||||||
|
<enum>Qt::RightToLeft</enum>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Download</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|
|
@ -1920,6 +1920,7 @@ void GMainWindow::OnLoadState() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GMainWindow::OnConfigure() {
|
void GMainWindow::OnConfigure() {
|
||||||
|
game_list->SetDirectoryWatcherEnabled(false);
|
||||||
Settings::SetConfiguringGlobal(true);
|
Settings::SetConfiguringGlobal(true);
|
||||||
ConfigureDialog configureDialog(this, hotkey_registry,
|
ConfigureDialog configureDialog(this, hotkey_registry,
|
||||||
!multiplayer_state->IsHostingPublicRoom());
|
!multiplayer_state->IsHostingPublicRoom());
|
||||||
|
@ -1931,6 +1932,7 @@ void GMainWindow::OnConfigure() {
|
||||||
const auto old_touch_from_button_maps = Settings::values.touch_from_button_maps;
|
const auto old_touch_from_button_maps = Settings::values.touch_from_button_maps;
|
||||||
const bool old_discord_presence = UISettings::values.enable_discord_presence.GetValue();
|
const bool old_discord_presence = UISettings::values.enable_discord_presence.GetValue();
|
||||||
auto result = configureDialog.exec();
|
auto result = configureDialog.exec();
|
||||||
|
game_list->SetDirectoryWatcherEnabled(true);
|
||||||
if (result == QDialog::Accepted) {
|
if (result == QDialog::Accepted) {
|
||||||
configureDialog.ApplyConfiguration();
|
configureDialog.ApplyConfiguration();
|
||||||
InitializeHotkeys();
|
InitializeHotkeys();
|
||||||
|
|
|
@ -16,8 +16,6 @@
|
||||||
|
|
||||||
namespace FileSys {
|
namespace FileSys {
|
||||||
|
|
||||||
constexpr u32 CIA_SECTION_ALIGNMENT = 0x40;
|
|
||||||
|
|
||||||
Loader::ResultStatus CIAContainer::Load(const FileBackend& backend) {
|
Loader::ResultStatus CIAContainer::Load(const FileBackend& backend) {
|
||||||
std::vector<u8> header_data(sizeof(Header));
|
std::vector<u8> header_data(sizeof(Header));
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ constexpr std::size_t CIA_CONTENT_BITS_SIZE = (CIA_CONTENT_MAX_COUNT / 8);
|
||||||
constexpr std::size_t CIA_HEADER_SIZE = 0x2020;
|
constexpr std::size_t CIA_HEADER_SIZE = 0x2020;
|
||||||
constexpr std::size_t CIA_DEPENDENCY_SIZE = 0x300;
|
constexpr std::size_t CIA_DEPENDENCY_SIZE = 0x300;
|
||||||
constexpr std::size_t CIA_METADATA_SIZE = 0x400;
|
constexpr std::size_t CIA_METADATA_SIZE = 0x400;
|
||||||
|
constexpr u32 CIA_SECTION_ALIGNMENT = 0x40;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper which implements an interface to read and write CTR Installable Archive (CIA) files.
|
* Helper which implements an interface to read and write CTR Installable Archive (CIA) files.
|
||||||
|
@ -69,7 +70,6 @@ public:
|
||||||
|
|
||||||
void Print() const;
|
void Print() const;
|
||||||
|
|
||||||
private:
|
|
||||||
struct Header {
|
struct Header {
|
||||||
u32_le header_size;
|
u32_le header_size;
|
||||||
u16_le type;
|
u16_le type;
|
||||||
|
@ -87,10 +87,14 @@ private:
|
||||||
// The bits in the content index are arranged w/ index 0 as the MSB, 7 as the LSB, etc.
|
// The bits in the content index are arranged w/ index 0 as the MSB, 7 as the LSB, etc.
|
||||||
return (content_present[index >> 3] & (0x80 >> (index & 7))) != 0;
|
return (content_present[index >> 3] & (0x80 >> (index & 7))) != 0;
|
||||||
}
|
}
|
||||||
|
void SetContentPresent(u16 index) {
|
||||||
|
content_present[index >> 3] |= (0x80 >> (index & 7));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(sizeof(Header) == CIA_HEADER_SIZE, "CIA Header structure size is wrong");
|
static_assert(sizeof(Header) == CIA_HEADER_SIZE, "CIA Header structure size is wrong");
|
||||||
|
|
||||||
|
private:
|
||||||
struct Metadata {
|
struct Metadata {
|
||||||
std::array<u64_le, 0x30> dependencies;
|
std::array<u64_le, 0x30> dependencies;
|
||||||
std::array<u8, 0x180> reserved;
|
std::array<u8, 0x180> reserved;
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <cryptopp/aes.h>
|
#include <cryptopp/aes.h>
|
||||||
#include <cryptopp/modes.h>
|
#include <cryptopp/modes.h>
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
#include "common/alignment.h"
|
||||||
#include "common/common_paths.h"
|
#include "common/common_paths.h"
|
||||||
#include "common/file_util.h"
|
#include "common/file_util.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
|
@ -31,6 +32,9 @@
|
||||||
#include "core/hle/service/fs/fs_user.h"
|
#include "core/hle/service/fs/fs_user.h"
|
||||||
#include "core/loader/loader.h"
|
#include "core/loader/loader.h"
|
||||||
#include "core/loader/smdh.h"
|
#include "core/loader/smdh.h"
|
||||||
|
#ifdef ENABLE_WEB_SERVICE
|
||||||
|
#include "web_service/nus_download.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Service::AM {
|
namespace Service::AM {
|
||||||
|
|
||||||
|
@ -138,6 +142,8 @@ ResultCode CIAFile::WriteTitleMetadata() {
|
||||||
decryption_state->content[i].SetKeyWithIV(title_key->data(), title_key->size(),
|
decryption_state->content[i].SetKeyWithIV(title_key->data(), title_key->size(),
|
||||||
ctr.data());
|
ctr.data());
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
LOG_ERROR(Service_AM, "Can't get title key from ticket");
|
||||||
}
|
}
|
||||||
|
|
||||||
install_state = CIAInstallState::TMDLoaded;
|
install_state = CIAInstallState::TMDLoaded;
|
||||||
|
@ -180,6 +186,11 @@ ResultVal<std::size_t> CIAFile::WriteContentData(u64 offset, std::size_t length,
|
||||||
buffer + (range_min - offset) + available_to_write);
|
buffer + (range_min - offset) + available_to_write);
|
||||||
|
|
||||||
if ((tmd.GetContentTypeByIndex(i) & FileSys::TMDContentTypeFlag::Encrypted) != 0) {
|
if ((tmd.GetContentTypeByIndex(i) & FileSys::TMDContentTypeFlag::Encrypted) != 0) {
|
||||||
|
if (decryption_state->content.size() <= i) {
|
||||||
|
// TODO: There is probably no correct error to return here. What error should be
|
||||||
|
// returned?
|
||||||
|
return FileSys::ERROR_INSUFFICIENT_SPACE;
|
||||||
|
}
|
||||||
decryption_state->content[i].ProcessData(temp.data(), temp.data(), temp.size());
|
decryption_state->content[i].ProcessData(temp.data(), temp.data(), temp.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,7 +246,7 @@ ResultVal<std::size_t> CIAFile::Write(u64 offset, std::size_t length, bool flush
|
||||||
std::size_t buf_offset = buf_loaded - offset;
|
std::size_t buf_offset = buf_loaded - offset;
|
||||||
std::size_t buf_copy_size =
|
std::size_t buf_copy_size =
|
||||||
std::min(length, static_cast<std::size_t>(container.GetContentOffset() - offset)) -
|
std::min(length, static_cast<std::size_t>(container.GetContentOffset() - offset)) -
|
||||||
buf_loaded;
|
buf_offset;
|
||||||
std::size_t buf_max_size = std::min(offset + length, container.GetContentOffset());
|
std::size_t buf_max_size = std::min(offset + length, container.GetContentOffset());
|
||||||
data.resize(buf_max_size);
|
data.resize(buf_max_size);
|
||||||
memcpy(data.data() + copy_offset, buffer + buf_offset, buf_copy_size);
|
memcpy(data.data() + copy_offset, buffer + buf_offset, buf_copy_size);
|
||||||
|
@ -418,6 +429,99 @@ InstallStatus InstallCIA(const std::string& path,
|
||||||
return InstallStatus::ErrorInvalid;
|
return InstallStatus::ErrorInvalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InstallStatus InstallFromNus(u64 title_id, int version) {
|
||||||
|
#ifdef ENABLE_WEB_SERVICE
|
||||||
|
LOG_DEBUG(Service_AM, "Downloading {:X}", title_id);
|
||||||
|
|
||||||
|
CIAFile install_file{GetTitleMediaType(title_id)};
|
||||||
|
|
||||||
|
std::string path = fmt::format("/ccs/download/{:016X}/tmd", title_id);
|
||||||
|
if (version != -1) {
|
||||||
|
path += fmt::format(".{}", version);
|
||||||
|
}
|
||||||
|
auto tmd_response = WebService::NUS::Download(path);
|
||||||
|
if (!tmd_response) {
|
||||||
|
LOG_ERROR(Service_AM, "Failed to download tmd for {:016X}", title_id);
|
||||||
|
return InstallStatus::ErrorFileNotFound;
|
||||||
|
}
|
||||||
|
FileSys::TitleMetadata tmd;
|
||||||
|
tmd.Load(*tmd_response);
|
||||||
|
|
||||||
|
path = fmt::format("/ccs/download/{:016X}/cetk", title_id);
|
||||||
|
auto cetk_response = WebService::NUS::Download(path);
|
||||||
|
if (!cetk_response) {
|
||||||
|
LOG_ERROR(Service_AM, "Failed to download cetk for {:016X}", title_id);
|
||||||
|
return InstallStatus::ErrorFileNotFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<u8> content;
|
||||||
|
const auto content_count = tmd.GetContentCount();
|
||||||
|
for (std::size_t i = 0; i < content_count; ++i) {
|
||||||
|
const std::string filename = fmt::format("{:08x}", tmd.GetContentIDByIndex(i));
|
||||||
|
path = fmt::format("/ccs/download/{:016X}/{}", title_id, filename);
|
||||||
|
const auto temp_response = WebService::NUS::Download(path);
|
||||||
|
if (!temp_response) {
|
||||||
|
LOG_ERROR(Service_AM, "Failed to download content for {:016X}", title_id);
|
||||||
|
return InstallStatus::ErrorFileNotFound;
|
||||||
|
}
|
||||||
|
content.insert(content.end(), temp_response->begin(), temp_response->end());
|
||||||
|
}
|
||||||
|
|
||||||
|
FileSys::CIAContainer::Header fake_header{
|
||||||
|
.header_size = sizeof(FileSys::CIAContainer::Header),
|
||||||
|
.type = 0,
|
||||||
|
.version = 0,
|
||||||
|
.cert_size = 0,
|
||||||
|
.tik_size = static_cast<u32_le>(cetk_response->size()),
|
||||||
|
.tmd_size = static_cast<u32_le>(tmd_response->size()),
|
||||||
|
.meta_size = 0,
|
||||||
|
};
|
||||||
|
for (u16 i = 0; i < content_count; ++i) {
|
||||||
|
fake_header.SetContentPresent(i);
|
||||||
|
}
|
||||||
|
std::vector<u8> header_data(sizeof(fake_header));
|
||||||
|
std::memcpy(header_data.data(), &fake_header, sizeof(fake_header));
|
||||||
|
|
||||||
|
std::size_t current_offset = 0;
|
||||||
|
const auto write_to_cia_file_aligned = [&install_file, ¤t_offset](std::vector<u8>& data) {
|
||||||
|
const u64 offset =
|
||||||
|
Common::AlignUp(current_offset + data.size(), FileSys::CIA_SECTION_ALIGNMENT);
|
||||||
|
data.resize(offset - current_offset, 0);
|
||||||
|
const auto result = install_file.Write(current_offset, data.size(), true, data.data());
|
||||||
|
if (result.Failed()) {
|
||||||
|
LOG_ERROR(Service_AM, "CIA file installation aborted with error code {:08x}",
|
||||||
|
result.Code().raw);
|
||||||
|
return InstallStatus::ErrorAborted;
|
||||||
|
}
|
||||||
|
current_offset += data.size();
|
||||||
|
return InstallStatus::Success;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto result = write_to_cia_file_aligned(header_data);
|
||||||
|
if (result != InstallStatus::Success) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = write_to_cia_file_aligned(*cetk_response);
|
||||||
|
if (result != InstallStatus::Success) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = write_to_cia_file_aligned(*tmd_response);
|
||||||
|
if (result != InstallStatus::Success) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = write_to_cia_file_aligned(content);
|
||||||
|
if (result != InstallStatus::Success) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return InstallStatus::Success;
|
||||||
|
#else
|
||||||
|
return InstallStatus::ErrorFileNotFound;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
Service::FS::MediaType GetTitleMediaType(u64 titleId) {
|
Service::FS::MediaType GetTitleMediaType(u64 titleId) {
|
||||||
u16 platform = static_cast<u16>(titleId >> 48);
|
u16 platform = static_cast<u16>(titleId >> 48);
|
||||||
u16 category = static_cast<u16>((titleId >> 32) & 0xFFFF);
|
u16 category = static_cast<u16>((titleId >> 32) & 0xFFFF);
|
||||||
|
|
|
@ -110,6 +110,13 @@ private:
|
||||||
InstallStatus InstallCIA(const std::string& path,
|
InstallStatus InstallCIA(const std::string& path,
|
||||||
std::function<ProgressCallback>&& update_callback = nullptr);
|
std::function<ProgressCallback>&& update_callback = nullptr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Downloads and installs title form the Nintendo Update Service.
|
||||||
|
* @param title_id the title_id to download
|
||||||
|
* @returns whether the install was successful or error code
|
||||||
|
*/
|
||||||
|
InstallStatus InstallFromNus(u64 title_id, int version = -1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the mediatype for an installed title
|
* Get the mediatype for an installed title
|
||||||
* @param titleId the installed title ID
|
* @param titleId the installed title ID
|
||||||
|
|
|
@ -88,7 +88,7 @@ struct KeySlot {
|
||||||
};
|
};
|
||||||
|
|
||||||
std::array<KeySlot, KeySlotID::MaxKeySlotID> key_slots;
|
std::array<KeySlot, KeySlotID::MaxKeySlotID> key_slots;
|
||||||
std::array<std::optional<AESKey>, 6> common_key_y_slots;
|
std::array<std::optional<AESKey>, MaxCommonKeySlot> common_key_y_slots;
|
||||||
|
|
||||||
enum class FirmwareType : u32 {
|
enum class FirmwareType : u32 {
|
||||||
ARM9 = 0, // uses NDMA
|
ARM9 = 0, // uses NDMA
|
||||||
|
@ -494,9 +494,9 @@ void LoadPresetKeys() {
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void InitKeys() {
|
void InitKeys(bool force) {
|
||||||
static bool initialized = false;
|
static bool initialized = false;
|
||||||
if (initialized)
|
if (initialized && !force)
|
||||||
return;
|
return;
|
||||||
initialized = true;
|
initialized = true;
|
||||||
HW::RSA::InitSlots();
|
HW::RSA::InitSlots();
|
||||||
|
|
|
@ -48,11 +48,13 @@ enum KeySlotID : std::size_t {
|
||||||
MaxKeySlotID = 0x40,
|
MaxKeySlotID = 0x40,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr std::size_t MaxCommonKeySlot = 6;
|
||||||
|
|
||||||
constexpr std::size_t AES_BLOCK_SIZE = 16;
|
constexpr std::size_t AES_BLOCK_SIZE = 16;
|
||||||
|
|
||||||
using AESKey = std::array<u8, AES_BLOCK_SIZE>;
|
using AESKey = std::array<u8, AES_BLOCK_SIZE>;
|
||||||
|
|
||||||
void InitKeys();
|
void InitKeys(bool force = false);
|
||||||
|
|
||||||
void SetGeneratorConstant(const AESKey& key);
|
void SetGeneratorConstant(const AESKey& key);
|
||||||
void SetKeyX(std::size_t slot_id, const AESKey& key);
|
void SetKeyX(std::size_t slot_id, const AESKey& key);
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
add_library(web_service STATIC
|
add_library(web_service STATIC
|
||||||
announce_room_json.cpp
|
announce_room_json.cpp
|
||||||
announce_room_json.h
|
announce_room_json.h
|
||||||
|
nus_download.cpp
|
||||||
|
nus_download.h
|
||||||
|
nus_titles.h
|
||||||
precompiled_headers.h
|
precompiled_headers.h
|
||||||
telemetry_json.cpp
|
telemetry_json.cpp
|
||||||
telemetry_json.h
|
telemetry_json.h
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
// Copyright 2020 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <httplib.h>
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
#include "web_service/nus_download.h"
|
||||||
|
|
||||||
|
namespace WebService::NUS {
|
||||||
|
|
||||||
|
std::optional<std::vector<u8>> Download(const std::string& path) {
|
||||||
|
constexpr auto HOST = "http://nus.cdn.c.shop.nintendowifi.net";
|
||||||
|
|
||||||
|
std::unique_ptr<httplib::Client> client = std::make_unique<httplib::Client>(HOST);
|
||||||
|
if (client == nullptr) {
|
||||||
|
LOG_ERROR(WebService, "Invalid URL {}{}", HOST, path);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
httplib::Request request{
|
||||||
|
.method = "GET",
|
||||||
|
.path = path,
|
||||||
|
};
|
||||||
|
|
||||||
|
client->set_follow_location(true);
|
||||||
|
const auto result = client->send(request);
|
||||||
|
if (!result) {
|
||||||
|
LOG_ERROR(WebService, "GET to {}{} returned null", HOST, path);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& response = result.value();
|
||||||
|
if (response.status >= 400) {
|
||||||
|
LOG_ERROR(WebService, "GET to {}{} returned error status code: {}", HOST, path,
|
||||||
|
response.status);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (!response.headers.contains("content-type")) {
|
||||||
|
LOG_ERROR(WebService, "GET to {}{} returned no content", HOST, path);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::vector<u8>(response.body.begin(), response.body.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace WebService::NUS
|
|
@ -0,0 +1,15 @@
|
||||||
|
// Copyright 2020 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
#include <vector>
|
||||||
|
#include "common/common_types.h"
|
||||||
|
|
||||||
|
namespace WebService::NUS {
|
||||||
|
|
||||||
|
std::optional<std::vector<u8>> Download(const std::string& path);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,761 @@
|
||||||
|
// Copyright 2023 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common/common_types.h"
|
||||||
|
|
||||||
|
constexpr u32 SYSTEM_FIRMWARE_UPPER_TITLE_ID = 0x00040138;
|
||||||
|
constexpr u32 SYSTEM_APPLICATION_UPPER_TITLE_ID = 0x00040010;
|
||||||
|
constexpr u32 SYSTEM_DATA_ARCHIVE_UPPER_TITLE_ID = 0x0004001B;
|
||||||
|
constexpr u32 SYSTEM_APPLET_UPPER_TITLE_ID = 0x00040030;
|
||||||
|
constexpr u32 SHARED_DATA_ARCHIVE_UPPER_TITLE_ID = 0x0004009B;
|
||||||
|
constexpr u32 SYSTEM_DATA_ARCHIVE_2_UPPER_TITLE_ID = 0x000400DB;
|
||||||
|
constexpr u32 SYSTEM_MODULE_UPPER_TITLE_ID = 0x00040130;
|
||||||
|
|
||||||
|
struct Title {
|
||||||
|
enum Mode { All, Recommended, Minimal };
|
||||||
|
std::string name;
|
||||||
|
u32 upper_title_id;
|
||||||
|
std::array<u32, 6> lower_title_id;
|
||||||
|
Mode mode = Mode::All;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const std::array<Title, 9> SYSTEM_FIRMWARE = {
|
||||||
|
{{"Safe Mode Native Firmware",
|
||||||
|
SYSTEM_FIRMWARE_UPPER_TITLE_ID,
|
||||||
|
{{0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003}},
|
||||||
|
Title::Mode::Minimal},
|
||||||
|
{"New_3DS Safe Mode Native Firmware",
|
||||||
|
SYSTEM_FIRMWARE_UPPER_TITLE_ID,
|
||||||
|
{{0x20000003, 0x20000003, 0x20000003, 0x20000003, 0x20000003, 0x20000003}},
|
||||||
|
Title::Mode::Minimal},
|
||||||
|
{"Native Firmware",
|
||||||
|
SYSTEM_FIRMWARE_UPPER_TITLE_ID,
|
||||||
|
{{0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002}},
|
||||||
|
Title::Mode::Minimal},
|
||||||
|
{"New_3DS Native Firmware",
|
||||||
|
SYSTEM_FIRMWARE_UPPER_TITLE_ID,
|
||||||
|
{{0x20000002, 0x20000002, 0x20000002, 0x20000002, 0x20000002, 0x20000002}},
|
||||||
|
Title::Mode::Minimal}}};
|
||||||
|
static const std::array<Title, 17> SYSTEM_APPLICATIONS = {
|
||||||
|
{{"System Settings",
|
||||||
|
SYSTEM_APPLICATION_UPPER_TITLE_ID,
|
||||||
|
{{0x00020000, 0x00021000, 0x00022000, 0x00026000, 0x00027000, 0x00028000}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Download Play",
|
||||||
|
SYSTEM_APPLICATION_UPPER_TITLE_ID,
|
||||||
|
{{0x00020100, 0x00021100, 0x00022100, 0x00026100, 0x00027100, 0x00028100}},
|
||||||
|
Title::Mode::Recommended},
|
||||||
|
{"Activity Log",
|
||||||
|
SYSTEM_APPLICATION_UPPER_TITLE_ID,
|
||||||
|
{{0x00020200, 0x00021200, 0x00022200, 0x00026200, 0x00027200, 0x00028200}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Health and Safety Information",
|
||||||
|
SYSTEM_APPLICATION_UPPER_TITLE_ID,
|
||||||
|
{{0x00020300, 0x00021300, 0x00022300, 0x00026300, 0x00027300, 0x00028300}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"New_3DS Health and Safety Information",
|
||||||
|
SYSTEM_APPLICATION_UPPER_TITLE_ID,
|
||||||
|
{{0x20020300, 0x20021300, 0x20022300, 0x0, 0x20027300, 0x0}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Nintendo 3DS Camera",
|
||||||
|
SYSTEM_APPLICATION_UPPER_TITLE_ID,
|
||||||
|
{{0x00020400, 0x00021400, 0x00022400, 0x00026400, 0x00027400, 0x00028400}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Nintendo 3DS Sound",
|
||||||
|
SYSTEM_APPLICATION_UPPER_TITLE_ID,
|
||||||
|
{{0x00020500, 0x00021500, 0x00022500, 0x00026500, 0x00027500, 0x00028500}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Mii Maker",
|
||||||
|
SYSTEM_APPLICATION_UPPER_TITLE_ID,
|
||||||
|
{{0x00020700, 0x00021700, 0x00022700, 0x00026700, 0x00027700, 0x00028700}},
|
||||||
|
Title::Mode::Recommended},
|
||||||
|
{"StreetPass Mii Plaza",
|
||||||
|
SYSTEM_APPLICATION_UPPER_TITLE_ID,
|
||||||
|
{{0x00020800, 0x00021800, 0x00022800, 0x00026800, 0x00027800, 0x00028800}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"eShop",
|
||||||
|
SYSTEM_APPLICATION_UPPER_TITLE_ID,
|
||||||
|
{{0x00020900, 0x00021900, 0x00022900, 0x0, 0x00027900, 0x00028900}},
|
||||||
|
Title::Mode::Recommended},
|
||||||
|
{"System Transfer",
|
||||||
|
SYSTEM_APPLICATION_UPPER_TITLE_ID,
|
||||||
|
{{0x00020A00, 0x00021A00, 0x00022A00, 0x0, 0x00027A00, 0x00028A00}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Nintendo Zone",
|
||||||
|
SYSTEM_APPLICATION_UPPER_TITLE_ID,
|
||||||
|
{{0x00020B00, 0x00021B00, 0x00022B00, 0x0, 0x0, 0x0}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Face Raiders",
|
||||||
|
SYSTEM_APPLICATION_UPPER_TITLE_ID,
|
||||||
|
{{0x00020D00, 0x00021D00, 0x00022D00, 0x00026D00, 0x00027D00, 0x00028D00}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"New_3DS Face Raiders",
|
||||||
|
SYSTEM_APPLICATION_UPPER_TITLE_ID,
|
||||||
|
{{0x20020D00, 0x20021D00, 0x20022D00, 0x0, 0x20027D00, 0x0}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"AR Games",
|
||||||
|
SYSTEM_APPLICATION_UPPER_TITLE_ID,
|
||||||
|
{{0x00020E00, 0x00021E00, 0x00022E00, 0x00026E00, 0x00027E00, 0x00028E00}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Nintendo Network ID Settings",
|
||||||
|
SYSTEM_APPLICATION_UPPER_TITLE_ID,
|
||||||
|
{{0x0002BF00, 0x0002C000, 0x0002C100, 0x0, 0x0, 0x0}},
|
||||||
|
Title::Mode::Recommended},
|
||||||
|
{"microSD Management",
|
||||||
|
SYSTEM_APPLICATION_UPPER_TITLE_ID,
|
||||||
|
{{0x20023100, 0x20024100, 0x20025100, 0x0, 0x0, 0x0}},
|
||||||
|
Title::Mode::All}}};
|
||||||
|
|
||||||
|
static const std::array<Title, 7> SYSTEM_DATA_ARCHIVES = {
|
||||||
|
{{"ClCertA",
|
||||||
|
SYSTEM_DATA_ARCHIVE_UPPER_TITLE_ID,
|
||||||
|
{{0x00010002, 0x00010002, 0x00010002, 0x00010002, 0x00010002, 0x00010002}},
|
||||||
|
Title::Mode::Recommended},
|
||||||
|
{"NS CFA",
|
||||||
|
SYSTEM_DATA_ARCHIVE_UPPER_TITLE_ID,
|
||||||
|
{{0x00010702, 0x00010702, 0x00010702, 0x00010702, 0x00010702, 0x00010702}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"dummy.txt",
|
||||||
|
SYSTEM_DATA_ARCHIVE_UPPER_TITLE_ID,
|
||||||
|
{{0x00010802, 0x00010802, 0x00010802, 0x00010802, 0x00010802, 0x00010802}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"CFA web-browser data",
|
||||||
|
SYSTEM_DATA_ARCHIVE_UPPER_TITLE_ID,
|
||||||
|
{{0x00018002, 0x00018002, 0x00018002, 0x00018002, 0x00018002, 0x00018002}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"local web-browser data",
|
||||||
|
SYSTEM_DATA_ARCHIVE_UPPER_TITLE_ID,
|
||||||
|
{{0x00018102, 0x00018102, 0x00018102, 0x00018102, 0x00018102, 0x00018102}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"webkit/OSS CROs",
|
||||||
|
SYSTEM_DATA_ARCHIVE_UPPER_TITLE_ID,
|
||||||
|
{{0x00018202, 0x00018202, 0x00018202, 0x00018202, 0x00018202, 0x00018202}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Fangate_updater",
|
||||||
|
SYSTEM_DATA_ARCHIVE_UPPER_TITLE_ID,
|
||||||
|
{{0x00019002, 0x00019002, 0x00019002, 0x00019002, 0x00019002, 0x00019002}},
|
||||||
|
Title::Mode::All}}};
|
||||||
|
|
||||||
|
static const std::array<Title, 27> SYSTEM_APPLETS = {
|
||||||
|
{{"Home Menu",
|
||||||
|
SYSTEM_APPLET_UPPER_TITLE_ID,
|
||||||
|
{{0x00008202, 0x00008F02, 0x00009802, 0x0000A102, 0x0000A902, 0x0000B102}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Camera applet",
|
||||||
|
SYSTEM_APPLET_UPPER_TITLE_ID,
|
||||||
|
{{0x00008402, 0x00009002, 0x00009902, 0x0000A202, 0x0000AA02, 0x0000B202}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Instruction Manual",
|
||||||
|
SYSTEM_APPLET_UPPER_TITLE_ID,
|
||||||
|
{{0x00008602, 0x00009202, 0x00009B02, 0x0000A402, 0x0000AC02, 0x0000B402}},
|
||||||
|
Title::Mode::Recommended},
|
||||||
|
{"Game Notes",
|
||||||
|
SYSTEM_APPLET_UPPER_TITLE_ID,
|
||||||
|
{{0x00008702, 0x00009302, 0x00009C02, 0x0000A502, 0x0000AD02, 0x0000B502}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Internet Browser",
|
||||||
|
SYSTEM_APPLET_UPPER_TITLE_ID,
|
||||||
|
{{0x00008802, 0x00009402, 0x00009D02, 0x0000A602, 0x0000AE02, 0x0000B602}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"New 3DS Internet Browser",
|
||||||
|
SYSTEM_APPLET_UPPER_TITLE_ID,
|
||||||
|
{{0x20008802, 0x20009402, 0x20009D02, 0x0, 0x2000AE02, 0x0}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Fatal error viewer",
|
||||||
|
SYSTEM_APPLET_UPPER_TITLE_ID,
|
||||||
|
{{0x00008A02, 0x00008A02, 0x00008A02, 0x00008A02, 0x00008A02, 0x00008A02}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Safe Mode Fatal error viewer",
|
||||||
|
SYSTEM_APPLET_UPPER_TITLE_ID,
|
||||||
|
{{0x00008A03, 0x00008A03, 0x00008A03, 0x00008A03, 0x00008A03, 0x00008A03}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"New 3DS Safe Mode Fatal error viewer",
|
||||||
|
SYSTEM_APPLET_UPPER_TITLE_ID,
|
||||||
|
{{0x20008A03, 0x20008A03, 0x20008A03, 0x0, 0x20008A03, 0x0}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Friend List",
|
||||||
|
SYSTEM_APPLET_UPPER_TITLE_ID,
|
||||||
|
{{0x00008D02, 0x00009602, 0x00009F02, 0x0000A702, 0x0000AF02, 0x0000B702}},
|
||||||
|
Title::Mode::Recommended},
|
||||||
|
{"Notifications",
|
||||||
|
SYSTEM_APPLET_UPPER_TITLE_ID,
|
||||||
|
{{0x00008E02, 0x000009702, 0x0000A002, 0x0000A802, 0x0000B002, 0x0000B802}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Software Keyboard",
|
||||||
|
SYSTEM_APPLET_UPPER_TITLE_ID,
|
||||||
|
{{0x00000C002, 0x0000C802, 0x0000D002, 0x0000D802, 0x0000DE02, 0x0000E402}},
|
||||||
|
Title::Mode::Recommended},
|
||||||
|
{"Safe Mode Software Keyboard",
|
||||||
|
SYSTEM_APPLET_UPPER_TITLE_ID,
|
||||||
|
{{0x00000C003, 0x0000C803, 0x0000D003, 0x0000D803, 0x0000DE03, 0x0000E403}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"New 3DS Safe Mode Software Keyboard",
|
||||||
|
SYSTEM_APPLET_UPPER_TITLE_ID,
|
||||||
|
{{0x2000C003, 0x2000C803, 0x2000D003, 0x0, 0x2000DE03, 0x0}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Mii picker",
|
||||||
|
SYSTEM_APPLET_UPPER_TITLE_ID,
|
||||||
|
{{0x0000C102, 0x0000C902, 0x0000D102, 0x0000D902, 0x0000DF02, 0x0000E502}},
|
||||||
|
Title::Mode::Recommended},
|
||||||
|
{"Picture picker",
|
||||||
|
SYSTEM_APPLET_UPPER_TITLE_ID,
|
||||||
|
{{0x0000C302, 0x0000CB02, 0x0000D302, 0x0000DB02, 0x0000E102, 0x0000E702}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Voice memo picker",
|
||||||
|
SYSTEM_APPLET_UPPER_TITLE_ID,
|
||||||
|
{{0x0000C402, 0x0000CC02, 0x0000D402, 0x0000DC02, 0x0000E202, 0x0000E802}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Error display",
|
||||||
|
SYSTEM_APPLET_UPPER_TITLE_ID,
|
||||||
|
{{0x0000C502, 0x0000C502, 0x0000C502, 0x0000CF02, 0x0000CF02, 0x0000CF02}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Safe mode error display",
|
||||||
|
SYSTEM_APPLET_UPPER_TITLE_ID,
|
||||||
|
{{0x0000C503, 0x0000C503, 0x0000C503, 0x0000CF03, 0x0000CF03, 0x0000CF03}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"New 3DS safe mode error display",
|
||||||
|
SYSTEM_APPLET_UPPER_TITLE_ID,
|
||||||
|
{{0x2000C503, 0x2000C503, 0x2000C503, 0x0, 0x2000CF03, 0x0}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Circle Pad Pro test/calibration applet",
|
||||||
|
SYSTEM_APPLET_UPPER_TITLE_ID,
|
||||||
|
{{0x0000CD02, 0x0000CD02, 0x0000CD02, 0x0000D502, 0x0000D502, 0x0000D502}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"eShop applet",
|
||||||
|
SYSTEM_APPLET_UPPER_TITLE_ID,
|
||||||
|
{{0x0000C602, 0x0000CE02, 0x0000D602, 0x0, 0x0000E302, 0x0000E902}},
|
||||||
|
Title::Mode::Recommended},
|
||||||
|
{"Miiverse",
|
||||||
|
SYSTEM_APPLET_UPPER_TITLE_ID,
|
||||||
|
{{0x0000BC02, 0x0000BC02, 0x0000BC02, 0x0, 0x0, 0x0}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Miiverse system library",
|
||||||
|
SYSTEM_APPLET_UPPER_TITLE_ID,
|
||||||
|
{{0x0000F602, 0x0000F602, 0x0000F602, 0x0, 0x0, 0x0}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Miiverse-posting applet",
|
||||||
|
SYSTEM_APPLET_UPPER_TITLE_ID,
|
||||||
|
{{0x00008302, 0x00008B02, 0x0000BA02, 0x0, 0x0, 0x0}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Amiibo Settings",
|
||||||
|
SYSTEM_APPLET_UPPER_TITLE_ID,
|
||||||
|
{{0x00009502, 0x00009E02, 0x0000B902, 0x0, 0x00008C02, 0x0000BF02}},
|
||||||
|
Title::Mode::All}}};
|
||||||
|
|
||||||
|
static const std::array<Title, 25> SHARED_DATA_ARCHIVES = {
|
||||||
|
{{"CFL_Res.dat",
|
||||||
|
SHARED_DATA_ARCHIVE_UPPER_TITLE_ID,
|
||||||
|
{{0x00010202, 0x00010202, 0x00010202, 0x00010202, 0x00010202, 0x00010202}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Region Manifest",
|
||||||
|
SHARED_DATA_ARCHIVE_UPPER_TITLE_ID,
|
||||||
|
{{0x00010402, 0x00010402, 0x00010402, 0x00010402, 0x00010402, 0x00010402}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Non-Nintendo TLS Root-CA Certificates",
|
||||||
|
SHARED_DATA_ARCHIVE_UPPER_TITLE_ID,
|
||||||
|
{{0x00010602, 0x00010602, 0x00010602, 0x00010602, 0x00010602, 0x00010602}},
|
||||||
|
Title::Mode::Recommended},
|
||||||
|
{"CHN/CN Dictionary",
|
||||||
|
SHARED_DATA_ARCHIVE_UPPER_TITLE_ID,
|
||||||
|
{{0x0, 0x0, 0x0, 0x00011002, 0x0, 0x0}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"TWN/TN dictionary",
|
||||||
|
SHARED_DATA_ARCHIVE_UPPER_TITLE_ID,
|
||||||
|
{{0x0, 0x0, 0x0, 0x0, 0x0, 0x00011102}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"NL/NL dictionary",
|
||||||
|
SHARED_DATA_ARCHIVE_UPPER_TITLE_ID,
|
||||||
|
{{0x0, 0x0, 0x00011202, 0x0, 0x0, 0x0}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"EN/GB dictionary",
|
||||||
|
SHARED_DATA_ARCHIVE_UPPER_TITLE_ID,
|
||||||
|
{{0x0, 0x0, 0x00011302, 0x0, 0x0, 0x0}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"EN/US dictionary",
|
||||||
|
SHARED_DATA_ARCHIVE_UPPER_TITLE_ID,
|
||||||
|
{{0x0, 0x00011402, 0x0, 0x0, 0x0, 0x0}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"FR/FR/regular dictionary",
|
||||||
|
SHARED_DATA_ARCHIVE_UPPER_TITLE_ID,
|
||||||
|
{{0x0, 0x0, 0x00011502, 0x0, 0x0, 0x0}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"FR/CA/regular dictionary",
|
||||||
|
SHARED_DATA_ARCHIVE_UPPER_TITLE_ID,
|
||||||
|
{{0x0, 0x00011602, 0x0, 0x0, 0x0, 0x0}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"DE/regular dictionary",
|
||||||
|
SHARED_DATA_ARCHIVE_UPPER_TITLE_ID,
|
||||||
|
{{0x0, 0x0, 0x00011702, 0x0, 0x0, 0x0}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"IT/IT dictionary",
|
||||||
|
SHARED_DATA_ARCHIVE_UPPER_TITLE_ID,
|
||||||
|
{{0x0, 0x0, 0x00011802, 0x0, 0x0, 0x0}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"JA_small/32 dictionary",
|
||||||
|
SHARED_DATA_ARCHIVE_UPPER_TITLE_ID,
|
||||||
|
{{0x00011902, 0x0, 0x0, 0x0, 0x0, 0x0}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"KO/KO dictionary",
|
||||||
|
SHARED_DATA_ARCHIVE_UPPER_TITLE_ID,
|
||||||
|
{{0x0, 0x0, 0x0, 0x0, 0x00011A02, 0x0}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"PT/PT/regular dictionary",
|
||||||
|
SHARED_DATA_ARCHIVE_UPPER_TITLE_ID,
|
||||||
|
{{0x0, 0x0, 0x00011B02, 0x0, 0x0, 0x0}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"RU/regular dictionary",
|
||||||
|
SHARED_DATA_ARCHIVE_UPPER_TITLE_ID,
|
||||||
|
{{0x0, 0x0, 0x00011C02, 0x0, 0x0, 0x0}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"ES/ES dictionary",
|
||||||
|
SHARED_DATA_ARCHIVE_UPPER_TITLE_ID,
|
||||||
|
{{0x0, 0x00011D02, 0x00011D02, 0x0, 0x0, 0x0}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"PT/BR/regular dictionary",
|
||||||
|
SHARED_DATA_ARCHIVE_UPPER_TITLE_ID,
|
||||||
|
{{0x0, 0x00011E02, 0x0, 0x0, 0x0, 0x0}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"error strings",
|
||||||
|
SHARED_DATA_ARCHIVE_UPPER_TITLE_ID,
|
||||||
|
{{0x00012202, 0x00012302, 0x00012102, 0x00012402, 0x00012502, 0x00012602}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"eula",
|
||||||
|
SHARED_DATA_ARCHIVE_UPPER_TITLE_ID,
|
||||||
|
{{0x00013202, 0x00013302, 0x00013102, 0x00013502, 0x0, 0x0}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"JPN/EUR/USA System Font",
|
||||||
|
SHARED_DATA_ARCHIVE_UPPER_TITLE_ID,
|
||||||
|
{{0x00014002, 0x00014002, 0x00014002, 0x00014002, 0x00014002, 0x00014002}},
|
||||||
|
Title::Mode::Recommended},
|
||||||
|
{"CHN System Font",
|
||||||
|
SHARED_DATA_ARCHIVE_UPPER_TITLE_ID,
|
||||||
|
{{0x00014102, 0x00014102, 0x00014102, 0x00014102, 0x00014102, 0x00014102}},
|
||||||
|
Title::Mode::Recommended},
|
||||||
|
{"KOR System Font",
|
||||||
|
SHARED_DATA_ARCHIVE_UPPER_TITLE_ID,
|
||||||
|
{{0x00014202, 0x00014202, 0x00014202, 0x00014202, 0x00014202, 0x00014202}},
|
||||||
|
Title::Mode::Recommended},
|
||||||
|
{"TWN System Font",
|
||||||
|
SHARED_DATA_ARCHIVE_UPPER_TITLE_ID,
|
||||||
|
{{0x00014302, 0x00014302, 0x00014302, 0x00014302, 0x00014302, 0x00014302}},
|
||||||
|
Title::Mode::Recommended},
|
||||||
|
{"rate",
|
||||||
|
SHARED_DATA_ARCHIVE_UPPER_TITLE_ID,
|
||||||
|
{{0x00015202, 0x00015302, 0x00015102, 0x0, 0x0015502, 0x00015602}},
|
||||||
|
Title::Mode::All}}};
|
||||||
|
|
||||||
|
static const std::array<Title, 5> SYSTEM_DATA_ARCHIVES_2 = {
|
||||||
|
{{"bad word list",
|
||||||
|
SYSTEM_DATA_ARCHIVE_2_UPPER_TITLE_ID,
|
||||||
|
{{0x00010302, 0x00010302, 0x00010302, 0x00010302, 0x00010302, 0x00010302}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Nintendo Zone hotspot list",
|
||||||
|
SYSTEM_DATA_ARCHIVE_2_UPPER_TITLE_ID,
|
||||||
|
{{0x00010502, 0x00010502, 0x00010502, 0x00010502, 0x00010502, 0x00010502}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"NVer",
|
||||||
|
SYSTEM_DATA_ARCHIVE_2_UPPER_TITLE_ID,
|
||||||
|
{{0x00016102, 0x00016202, 0x00016302, 0x00016402, 0x00016502, 0x00016602}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"New_3DS NVer",
|
||||||
|
SYSTEM_DATA_ARCHIVE_2_UPPER_TITLE_ID,
|
||||||
|
{{0x20016102, 0x20016202, 0x20016302, 0x0, 0x20016502, 0x0}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"CVer",
|
||||||
|
SYSTEM_DATA_ARCHIVE_2_UPPER_TITLE_ID,
|
||||||
|
{{0x00017102, 0x00017202, 0x00017302, 0x00017402, 0x00017502, 0x00017602}},
|
||||||
|
Title::Mode::All}}};
|
||||||
|
|
||||||
|
static const std::array<Title, 100> SYSTEM_MODULES = {
|
||||||
|
{{"AM ( Application Manager )",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00001502, 0x00001502, 0x00001502, 0x00001502, 0x00001502, 0x00001502}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Safe Mode AM",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00001503, 0x00001503, 0x00001503, 0x00001503, 0x00001503, 0x00001503}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"New_3DS Safe Mode AM",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x20001503, 0x20001503, 0x20001503, 0x20001503, 0x20001503, 0x20001503}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Camera",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00001602, 0x00001602, 0x00001602, 0x00001602, 0x00001602, 0x00001602}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"New_3DS Camera",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x20001602, 0x20001602, 0x20001602, 0x20001602, 0x20001602, 0x20001602}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Config (cfg)",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00001702, 0x00001702, 0x00001702, 0x00001702, 0x00001702, 0x00001702}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Safe Mode Config (cfg)",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00001703, 0x00001703, 0x00001703, 0x00001703, 0x00001703, 0x00001703}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"New_3DS Safe Mode Config (cfg)",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x20001703, 0x20001703, 0x20001703, 0x20001703, 0x20001703, 0x20001703}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Codec",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00001802, 0x00001802, 0x00001802, 0x00001802, 0x00001802, 0x00001802}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Safe Mode Codec",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00001803, 0x00001803, 0x00001803, 0x00001803, 0x00001803, 0x00001803}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"New_3DS Safe Mode Codec",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x20001803, 0x20001803, 0x20001803, 0x20001803, 0x20001803, 0x20001803}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"DSP",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00001A02, 0x00001A02, 0x00001A02, 0x00001A02, 0x00001A02, 0x00001A02}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Safe Mode DSP",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00001A03, 0x00001A03, 0x00001A03, 0x00001A03, 0x00001A03, 0x00001A03}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"New_3DS Safe Mode DSP",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x20001A03, 0x20001A03, 0x20001A03, 0x20001A03, 0x20001A03, 0x20001A03}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"GPIO",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00001B02, 0x00001B02, 0x00001B02, 0x00001B02, 0x00001B02, 0x00001B02}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Safe Mode GPIO",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00001B03, 0x00001B03, 0x00001B03, 0x00001B03, 0x00001B03, 0x00001B03}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"New_3DS Safe Mode GPIO",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x20001B03, 0x20001B03, 0x20001B03, 0x20001B03, 0x20001B03, 0x20001B03}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"GSP",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00001C02, 0x00001C02, 0x00001C02, 0x00001C02, 0x00001C02, 0x00001C02}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"New_3DS GSP",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x20001C02, 0x20001C02, 0x20001C02, 0x20001C02, 0x20001C02, 0x20001C02}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Safe Mode GSP",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00001C03, 0x00001C03, 0x00001C03, 0x00001C03, 0x00001C03, 0x00001C03}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"New_3DS Safe Mode GSP",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x20001C03, 0x20001C03, 0x20001C03, 0x20001C03, 0x20001C03, 0x20001C03}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"HID (Human Interface Devices)",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00001D02, 0x00001D02, 0x00001D02, 0x00001D02, 0x00001D02, 0x00001D02}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Safe Mode HID",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00001D03, 0x00001D03, 0x00001D03, 0x00001D03, 0x00001D03, 0x00001D03}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"New_3DS Safe Mode HID",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x20001D03, 0x20001D03, 0x20001D03, 0x20001D03, 0x20001D03, 0x20001D03}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"i2c",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00001E02, 0x00001E02, 0x00001E02, 0x00001E02, 0x00001E02, 0x00001E02}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"New_3DS i2c",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x20001E02, 0x20001E02, 0x20001E02, 0x20001E02, 0x20001E02, 0x20001E02}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Safe Mode i2c",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00001E03, 0x00001E03, 0x00001E03, 0x00001E03, 0x00001E03, 0x00001E03}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"New_3DS Safe Mode i2c",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x20001E03, 0x20001E03, 0x20001E03, 0x20001E03, 0x20001E03, 0x20001E03}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"MCU",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00001F02, 0x00001F02, 0x00001F02, 0x00001F02, 0x00001F02, 0x00001F02}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"New_3DS MCU",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x20001F02, 0x20001F02, 0x20001F02, 0x20001F02, 0x20001F02, 0x20001F02}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Safe Mode MCU",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00001F03, 0x00001F03, 0x00001F03, 0x00001F03, 0x00001F03, 0x00001F03}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"New_3DS Safe Mode MCU",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x20001F03, 0x20001F03, 0x20001F03, 0x20001F03, 0x20001F03, 0x20001F03}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"MIC (Microphone)",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00002002, 0x00002002, 0x00002002, 0x00002002, 0x00002002, 0x00002002}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"PDN",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00002102, 0x00002102, 0x00002102, 0x00002102, 0x00002102, 0x00002102}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Safe Mode PDN",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00002103, 0x00002103, 0x00002103, 0x00002103, 0x00002103, 0x00002103}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"New_3DS Safe Mode PDN",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x20002103, 0x20002103, 0x20002103, 0x20002103, 0x20002103, 0x20002103}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"PTM (Play time, pedometer, and battery manager)",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00002202, 0x00002202, 0x00002202, 0x00002202, 0x00002202, 0x00002202}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"New_3DS PTM (Play time, pedometer, and battery manager)",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x20002202, 0x20002202, 0x20002202, 0x20002202, 0x20002202, 0x20002202}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Safe Mode PTM",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00002203, 0x00002203, 0x00002203, 0x00002203, 0x00002203, 0x00002203}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"New_3DS Safe Mode PTM",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x20002203, 0x20002203, 0x20002203, 0x20002203, 0x20002203, 0x20002203}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"spi",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00002302, 0x00002302, 0x00002302, 0x00002302, 0x00002302, 0x00002302}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"New_3DS spi",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x20002302, 0x20002302, 0x20002302, 0x20002302, 0x20002302, 0x20002302}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Safe Mode spi",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00002303, 0x00002303, 0x00002303, 0x00002303, 0x00002303, 0x00002303}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"New_3DS Safe Mode spi",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x20002303, 0x20002303, 0x20002303, 0x20002303, 0x20002303, 0x20002303}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"AC (Network manager)",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00002402, 0x00002402, 0x00002402, 0x00002402, 0x00002402, 0x00002402}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Safe Mode AC",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00002403, 0x00002403, 0x00002403, 0x00002403, 0x00002403, 0x00002403}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"New_3DS Safe Mode AC",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x20002403, 0x20002403, 0x20002403, 0x20002403, 0x20002403, 0x20002403}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Cecd (StreetPass)",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00002602, 0x00002602, 0x00002602, 0x00002602, 0x00002602, 0x00002602}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"CSND",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00002702, 0x00002702, 0x00002702, 0x00002702, 0x00002702, 0x00002702}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Safe Mode CSND",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00002703, 0x00002703, 0x00002703, 0x00002703, 0x00002703, 0x00002703}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"New_3DS Safe Mode CSND",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x20002703, 0x20002703, 0x20002703, 0x20002703, 0x20002703, 0x20002703}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"DLP (Download Play)",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00002802, 0x00002802, 0x00002802, 0x00002802, 0x00002802, 0x00002802}},
|
||||||
|
Title::Mode::Recommended},
|
||||||
|
{"HTTP",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00002902, 0x00002902, 0x00002902, 0x00002902, 0x00002902, 0x00002902}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Safe Mode HTTP",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00002903, 0x00002903, 0x00002903, 0x00002903, 0x00002903, 0x00002903}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"New_3DS Safe Mode HTTP",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x20002903, 0x20002903, 0x20002903, 0x20002903, 0x20002903, 0x20002903}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"MP",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00002A02, 0x00002A02, 0x00002A02, 0x00002A02, 0x00002A02, 0x00002A02}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Safe Mode MP",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00002A03, 0x00002A03, 0x00002A03, 0x00002A03, 0x00002A03, 0x00002A03}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"NDM",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00002B02, 0x00002B02, 0x00002B02, 0x00002B02, 0x00002B02, 0x00002B02}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"NIM",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00002C02, 0x00002C02, 0x00002C02, 0x00002C02, 0x00002C02, 0x00002C02}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Safe Mode NIM",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00002C03, 0x00002C03, 0x00002C03, 0x00002C03, 0x00002C03, 0x00002C03}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"New_3DS Safe Mode NIM",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x20002C03, 0x20002C03, 0x20002C03, 0x20002C03, 0x20002C03, 0x20002C03}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"NWM ( Low-level wifi manager )",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00002D02, 0x00002D02, 0x00002D02, 0x00002D02, 0x00002D02, 0x00002D02}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Safe Mode NWM",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00002D03, 0x00002D03, 0x00002D03, 0x00002D03, 0x00002D03, 0x00002D03}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"New_3DS Safe Mode NWM",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x20002D03, 0x20002D03, 0x20002D03, 0x20002D03, 0x20002D03, 0x20002D03}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Sockets",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00002E02, 0x00002E02, 0x00002E02, 0x00002E02, 0x00002E02, 0x00002E02}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Safe Mode Sockets",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00002E03, 0x00002E03, 0x00002E03, 0x00002E03, 0x00002E03, 0x00002E03}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"New_3DS Safe Mode Sockets",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x20002E03, 0x20002E03, 0x20002E03, 0x20002E03, 0x20002E03, 0x20002E03}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"SSL",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00002F02, 0x00002F02, 0x00002F02, 0x00002F02, 0x00002F02, 0x00002F02}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Safe Mode SSL",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00002F03, 0x00002F03, 0x00002F03, 0x00002F03, 0x00002F03, 0x00002F03}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"New_3DS Safe Mode SSL",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x20002F03, 0x20002F03, 0x20002F03, 0x20002F03, 0x20002F03, 0x20002F03}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"PS ( Process Manager )",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00003102, 0x00003102, 0x00003102, 0x00003102, 0x00003102, 0x00003102}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Safe Mode PS",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00003103, 0x00003103, 0x00003103, 0x00003103, 0x00003103, 0x00003103}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"New_3DS Safe Mode PS",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x20003103, 0x20003103, 0x20003103, 0x20003103, 0x20003103, 0x20003103}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"friends (Friends list)",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00003202, 0x00003202, 0x00003202, 0x00003202, 0x00003202, 0x00003202}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Safe Mode friends (Friends list)",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00003203, 0x00003203, 0x00003203, 0x00003203, 0x00003203, 0x00003203}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"New_3DS Safe Mode friends (Friends list)",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x20003203, 0x20003203, 0x20003203, 0x20003203, 0x20003203, 0x20003203}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"IR (Infrared)",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00003302, 0x00003302, 0x00003302, 0x00003302, 0x00003302, 0x00003302}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Safe Mode IR",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00003303, 0x00003303, 0x00003303, 0x00003303, 0x00003303, 0x00003303}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"New_3DS Safe Mode IR",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x20003303, 0x20003303, 0x20003303, 0x20003303, 0x20003303, 0x20003303}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"BOSS (SpotPass)",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00003402, 0x00003402, 0x00003402, 0x00003402, 0x00003402, 0x00003402}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"News (Notifications)",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00003502, 0x00003502, 0x00003502, 0x00003502, 0x00003502, 0x00003502}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"RO",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00003702, 0x00003702, 0x00003702, 0x00003702, 0x00003702, 0x00003702}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"act",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00003802, 0x00003802, 0x00003802, 0x00003802, 0x00003802, 0x00003802}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"nfc",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00004002, 0x00004002, 0x00004002, 0x00004002, 0x00004002, 0x00004002}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"New_3DS mvd",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x20004102, 0x20004102, 0x20004102, 0x20004102, 0x20004102, 0x20004102}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"New_3DS qtm",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x20004202, 0x20004202, 0x20004202, 0x20004202, 0x20004202, 0x20004202}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"NS",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00008002, 0x00008002, 0x00008002, 0x00008002, 0x00008002, 0x00008002}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"Safe Mode NS",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x00008003, 0x00008003, 0x00008003, 0x00008003, 0x00008003, 0x00008003}},
|
||||||
|
Title::Mode::All},
|
||||||
|
{"New_3DS Safe Mode NS",
|
||||||
|
SYSTEM_MODULE_UPPER_TITLE_ID,
|
||||||
|
{{0x20008003, 0x20008003, 0x20008003, 0x20008003, 0x20008003, 0x20008003}},
|
||||||
|
Title::Mode::All}}};
|
||||||
|
|
||||||
|
std::vector<u64> BuildFirmwareTitleList(const Title::Mode& mode, u32 region) {
|
||||||
|
// Since Australia and Europe share the same title,
|
||||||
|
// offset down by one for Australia and above.
|
||||||
|
const u32 region_index = region >= 3 ? region - 1 : region;
|
||||||
|
|
||||||
|
const auto titles_with_mode = [mode, region_index](const Title& title) {
|
||||||
|
return mode <= title.mode && title.lower_title_id[region_index] != 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<Title> titles;
|
||||||
|
const auto inserter = std::back_inserter(titles);
|
||||||
|
std::copy_if(SYSTEM_FIRMWARE.begin(), SYSTEM_FIRMWARE.end(), inserter, titles_with_mode);
|
||||||
|
std::copy_if(SYSTEM_APPLICATIONS.begin(), SYSTEM_APPLICATIONS.end(), inserter,
|
||||||
|
titles_with_mode);
|
||||||
|
std::copy_if(SYSTEM_DATA_ARCHIVES.begin(), SYSTEM_DATA_ARCHIVES.end(), inserter,
|
||||||
|
titles_with_mode);
|
||||||
|
std::copy_if(SYSTEM_APPLETS.begin(), SYSTEM_APPLETS.end(), inserter, titles_with_mode);
|
||||||
|
std::copy_if(SHARED_DATA_ARCHIVES.begin(), SHARED_DATA_ARCHIVES.end(), inserter,
|
||||||
|
titles_with_mode);
|
||||||
|
std::copy_if(SYSTEM_DATA_ARCHIVES_2.begin(), SYSTEM_DATA_ARCHIVES_2.end(), inserter,
|
||||||
|
titles_with_mode);
|
||||||
|
std::copy_if(SYSTEM_MODULES.begin(), SYSTEM_MODULES.end(), inserter, titles_with_mode);
|
||||||
|
|
||||||
|
const auto get_title_id = [region_index](const Title& title) {
|
||||||
|
return (static_cast<u64>(title.upper_title_id) << 32) +
|
||||||
|
static_cast<u64>(title.lower_title_id[region_index]);
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<u64> title_ids;
|
||||||
|
std::transform(titles.begin(), titles.end(), std::back_inserter(title_ids), get_title_id);
|
||||||
|
return title_ids;
|
||||||
|
}
|
Reference in New Issue