mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	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
					
				
					 16 changed files with 1076 additions and 10 deletions
				
			
		|  | @ -209,7 +209,7 @@ if (ENABLE_QT) | |||
|         set(QT_PREFIX_HINT) | ||||
|     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) | ||||
|         find_package(Qt5 REQUIRED COMPONENTS LinguistTools ${QT_PREFIX_HINT}) | ||||
|  |  | |||
|  | @ -266,7 +266,7 @@ endif() | |||
| 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 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_compile_definitions(citra-qt PRIVATE | ||||
|  |  | |||
|  | @ -3,14 +3,22 @@ | |||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <cstring> | ||||
| #include <QFutureWatcher> | ||||
| #include <QMessageBox> | ||||
| #include <QProgressDialog> | ||||
| #include <QtConcurrent/QtConcurrentMap> | ||||
| #include "citra_qt/configuration/configuration_shared.h" | ||||
| #include "citra_qt/configuration/configure_system.h" | ||||
| #include "common/settings.h" | ||||
| #include "core/core.h" | ||||
| #include "core/hle/service/am/am.h" | ||||
| #include "core/hle/service/cfg/cfg.h" | ||||
| #include "core/hle/service/ptm/ptm.h" | ||||
| #include "core/hw/aes/key.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 = {{ | ||||
|     31, | ||||
|  | @ -239,6 +247,8 @@ ConfigureSystem::ConfigureSystem(QWidget* parent) | |||
|             &ConfigureSystem::UpdateInitTime); | ||||
|     connect(ui->button_regenerate_console_id, &QPushButton::clicked, this, | ||||
|             &ConfigureSystem::RefreshConsoleID); | ||||
|     connect(ui->button_start_download, &QPushButton::clicked, this, | ||||
|             &ConfigureSystem::DownloadFromNUS); | ||||
|     for (u8 i = 0; i < country_names.size(); i++) { | ||||
|         if (std::strcmp(country_names.at(i), "") != 0) { | ||||
|             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()); | ||||
| 
 | ||||
|     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(); | ||||
| } | ||||
| 
 | ||||
|  | @ -542,3 +576,44 @@ void ConfigureSystem::SetupPerGameUI() { | |||
|     ConfigurationShared::SetColoredTristate(ui->toggle_new_3ds, Settings::values.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 DownloadFromNUS(); | ||||
| 
 | ||||
|     ConfigurationShared::CheckState is_new_3ds; | ||||
|     std::unique_ptr<Ui::ConfigureSystem> ui; | ||||
|     bool enabled = false; | ||||
|  |  | |||
|  | @ -361,6 +361,52 @@ | |||
|             </property> | ||||
|           </widget> | ||||
|         </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> | ||||
|       </widget> | ||||
|      </item> | ||||
|  |  | |||
|  | @ -1920,6 +1920,7 @@ void GMainWindow::OnLoadState() { | |||
| } | ||||
| 
 | ||||
| void GMainWindow::OnConfigure() { | ||||
|     game_list->SetDirectoryWatcherEnabled(false); | ||||
|     Settings::SetConfiguringGlobal(true); | ||||
|     ConfigureDialog configureDialog(this, hotkey_registry, | ||||
|                                     !multiplayer_state->IsHostingPublicRoom()); | ||||
|  | @ -1931,6 +1932,7 @@ void GMainWindow::OnConfigure() { | |||
|     const auto old_touch_from_button_maps = Settings::values.touch_from_button_maps; | ||||
|     const bool old_discord_presence = UISettings::values.enable_discord_presence.GetValue(); | ||||
|     auto result = configureDialog.exec(); | ||||
|     game_list->SetDirectoryWatcherEnabled(true); | ||||
|     if (result == QDialog::Accepted) { | ||||
|         configureDialog.ApplyConfiguration(); | ||||
|         InitializeHotkeys(); | ||||
|  |  | |||
|  | @ -16,8 +16,6 @@ | |||
| 
 | ||||
| namespace FileSys { | ||||
| 
 | ||||
| constexpr u32 CIA_SECTION_ALIGNMENT = 0x40; | ||||
| 
 | ||||
| Loader::ResultStatus CIAContainer::Load(const FileBackend& backend) { | ||||
|     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_DEPENDENCY_SIZE = 0x300; | ||||
| 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. | ||||
|  | @ -69,7 +70,6 @@ public: | |||
| 
 | ||||
|     void Print() const; | ||||
| 
 | ||||
| private: | ||||
|     struct Header { | ||||
|         u32_le header_size; | ||||
|         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.
 | ||||
|             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"); | ||||
| 
 | ||||
| private: | ||||
|     struct Metadata { | ||||
|         std::array<u64_le, 0x30> dependencies; | ||||
|         std::array<u8, 0x180> reserved; | ||||
|  |  | |||
|  | @ -9,6 +9,7 @@ | |||
| #include <cryptopp/aes.h> | ||||
| #include <cryptopp/modes.h> | ||||
| #include <fmt/format.h> | ||||
| #include "common/alignment.h" | ||||
| #include "common/common_paths.h" | ||||
| #include "common/file_util.h" | ||||
| #include "common/logging/log.h" | ||||
|  | @ -31,6 +32,9 @@ | |||
| #include "core/hle/service/fs/fs_user.h" | ||||
| #include "core/loader/loader.h" | ||||
| #include "core/loader/smdh.h" | ||||
| #ifdef ENABLE_WEB_SERVICE | ||||
| #include "web_service/nus_download.h" | ||||
| #endif | ||||
| 
 | ||||
| namespace Service::AM { | ||||
| 
 | ||||
|  | @ -138,6 +142,8 @@ ResultCode CIAFile::WriteTitleMetadata() { | |||
|             decryption_state->content[i].SetKeyWithIV(title_key->data(), title_key->size(), | ||||
|                                                       ctr.data()); | ||||
|         } | ||||
|     } else { | ||||
|         LOG_ERROR(Service_AM, "Can't get title key from ticket"); | ||||
|     } | ||||
| 
 | ||||
|     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); | ||||
| 
 | ||||
|             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()); | ||||
|             } | ||||
| 
 | ||||
|  | @ -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_copy_size = | ||||
|             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()); | ||||
|         data.resize(buf_max_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; | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
|     u16 platform = static_cast<u16>(titleId >> 48); | ||||
|     u16 category = static_cast<u16>((titleId >> 32) & 0xFFFF); | ||||
|  |  | |||
|  | @ -110,6 +110,13 @@ private: | |||
| InstallStatus InstallCIA(const std::string& path, | ||||
|                          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 | ||||
|  * @param titleId the installed title ID | ||||
|  |  | |||
|  | @ -88,7 +88,7 @@ struct KeySlot { | |||
| }; | ||||
| 
 | ||||
| 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 { | ||||
|     ARM9 = 0,  // uses NDMA
 | ||||
|  | @ -494,9 +494,9 @@ void LoadPresetKeys() { | |||
| 
 | ||||
| } // namespace
 | ||||
| 
 | ||||
| void InitKeys() { | ||||
| void InitKeys(bool force) { | ||||
|     static bool initialized = false; | ||||
|     if (initialized) | ||||
|     if (initialized && !force) | ||||
|         return; | ||||
|     initialized = true; | ||||
|     HW::RSA::InitSlots(); | ||||
|  |  | |||
|  | @ -48,11 +48,13 @@ enum KeySlotID : std::size_t { | |||
|     MaxKeySlotID = 0x40, | ||||
| }; | ||||
| 
 | ||||
| constexpr std::size_t MaxCommonKeySlot = 6; | ||||
| 
 | ||||
| constexpr std::size_t AES_BLOCK_SIZE = 16; | ||||
| 
 | ||||
| using AESKey = std::array<u8, AES_BLOCK_SIZE>; | ||||
| 
 | ||||
| void InitKeys(); | ||||
| void InitKeys(bool force = false); | ||||
| 
 | ||||
| void SetGeneratorConstant(const AESKey& key); | ||||
| void SetKeyX(std::size_t slot_id, const AESKey& key); | ||||
|  |  | |||
|  | @ -1,6 +1,9 @@ | |||
| add_library(web_service STATIC | ||||
|     announce_room_json.cpp | ||||
|     announce_room_json.h | ||||
|     nus_download.cpp | ||||
|     nus_download.h | ||||
|     nus_titles.h | ||||
|     precompiled_headers.h | ||||
|     telemetry_json.cpp | ||||
|     telemetry_json.h | ||||
|  |  | |||
							
								
								
									
										47
									
								
								src/web_service/nus_download.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/web_service/nus_download.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -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
 | ||||
							
								
								
									
										15
									
								
								src/web_service/nus_download.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/web_service/nus_download.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -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); | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										761
									
								
								src/web_service/nus_titles.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										761
									
								
								src/web_service/nus_titles.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -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; | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue