diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/kernel/process.cpp | 6 | ||||
| -rw-r--r-- | src/core/hle/kernel/vm_manager.cpp | 20 | ||||
| -rw-r--r-- | src/core/hle/kernel/vm_manager.h | 8 | ||||
| -rw-r--r-- | src/core/hle/service/ldr/ldr.cpp | 52 | ||||
| -rw-r--r-- | src/core/hle/service/nfp/nfp.cpp | 6 | ||||
| -rw-r--r-- | src/core/hle/service/nfp/nfp.h | 2 | ||||
| -rw-r--r-- | src/core/loader/nro.cpp | 21 | ||||
| -rw-r--r-- | src/core/loader/nro.h | 3 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_system.cpp | 56 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_system.h | 35 | ||||
| -rw-r--r-- | src/yuzu/main.cpp | 49 |
11 files changed, 187 insertions, 71 deletions
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 073dd5a7d..420218d59 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp | |||
| @@ -232,6 +232,12 @@ void Process::LoadModule(CodeSet module_, VAddr base_addr) { | |||
| 232 | MapSegment(module_.CodeSegment(), VMAPermission::ReadExecute, MemoryState::CodeStatic); | 232 | MapSegment(module_.CodeSegment(), VMAPermission::ReadExecute, MemoryState::CodeStatic); |
| 233 | MapSegment(module_.RODataSegment(), VMAPermission::Read, MemoryState::CodeMutable); | 233 | MapSegment(module_.RODataSegment(), VMAPermission::Read, MemoryState::CodeMutable); |
| 234 | MapSegment(module_.DataSegment(), VMAPermission::ReadWrite, MemoryState::CodeMutable); | 234 | MapSegment(module_.DataSegment(), VMAPermission::ReadWrite, MemoryState::CodeMutable); |
| 235 | |||
| 236 | // Clear instruction cache in CPU JIT | ||
| 237 | Core::System::GetInstance().ArmInterface(0).ClearInstructionCache(); | ||
| 238 | Core::System::GetInstance().ArmInterface(1).ClearInstructionCache(); | ||
| 239 | Core::System::GetInstance().ArmInterface(2).ClearInstructionCache(); | ||
| 240 | Core::System::GetInstance().ArmInterface(3).ClearInstructionCache(); | ||
| 235 | } | 241 | } |
| 236 | 242 | ||
| 237 | ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission perms) { | 243 | ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission perms) { |
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index e1a34eef1..1a92c8f70 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp | |||
| @@ -143,6 +143,26 @@ ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8* me | |||
| 143 | return MakeResult<VMAHandle>(MergeAdjacent(vma_handle)); | 143 | return MakeResult<VMAHandle>(MergeAdjacent(vma_handle)); |
| 144 | } | 144 | } |
| 145 | 145 | ||
| 146 | ResultVal<VAddr> VMManager::FindFreeRegion(u64 size) const { | ||
| 147 | // Find the first Free VMA. | ||
| 148 | const VAddr base = GetASLRRegionBaseAddress(); | ||
| 149 | const VMAHandle vma_handle = std::find_if(vma_map.begin(), vma_map.end(), [&](const auto& vma) { | ||
| 150 | if (vma.second.type != VMAType::Free) | ||
| 151 | return false; | ||
| 152 | |||
| 153 | const VAddr vma_end = vma.second.base + vma.second.size; | ||
| 154 | return vma_end > base && vma_end >= base + size; | ||
| 155 | }); | ||
| 156 | |||
| 157 | if (vma_handle == vma_map.end()) { | ||
| 158 | // TODO(Subv): Find the correct error code here. | ||
| 159 | return ResultCode(-1); | ||
| 160 | } | ||
| 161 | |||
| 162 | const VAddr target = std::max(base, vma_handle->second.base); | ||
| 163 | return MakeResult<VAddr>(target); | ||
| 164 | } | ||
| 165 | |||
| 146 | ResultVal<VMManager::VMAHandle> VMManager::MapMMIO(VAddr target, PAddr paddr, u64 size, | 166 | ResultVal<VMManager::VMAHandle> VMManager::MapMMIO(VAddr target, PAddr paddr, u64 size, |
| 147 | MemoryState state, | 167 | MemoryState state, |
| 148 | Memory::MemoryHookPointer mmio_handler) { | 168 | Memory::MemoryHookPointer mmio_handler) { |
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h index 84c890224..2447cbb8f 100644 --- a/src/core/hle/kernel/vm_manager.h +++ b/src/core/hle/kernel/vm_manager.h | |||
| @@ -158,6 +158,14 @@ public: | |||
| 158 | ResultVal<VMAHandle> MapBackingMemory(VAddr target, u8* memory, u64 size, MemoryState state); | 158 | ResultVal<VMAHandle> MapBackingMemory(VAddr target, u8* memory, u64 size, MemoryState state); |
| 159 | 159 | ||
| 160 | /** | 160 | /** |
| 161 | * Finds the first free address that can hold a region of the desired size. | ||
| 162 | * | ||
| 163 | * @param size Size of the desired region. | ||
| 164 | * @return The found free address. | ||
| 165 | */ | ||
| 166 | ResultVal<VAddr> FindFreeRegion(u64 size) const; | ||
| 167 | |||
| 168 | /** | ||
| 161 | * Maps a memory-mapped IO region at a given address. | 169 | * Maps a memory-mapped IO region at a given address. |
| 162 | * | 170 | * |
| 163 | * @param target The guest address to start the mapping at. | 171 | * @param target The guest address to start the mapping at. |
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index ec32faf15..d607d985e 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp | |||
| @@ -3,9 +3,13 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <memory> | 5 | #include <memory> |
| 6 | #include <fmt/format.h> | ||
| 6 | 7 | ||
| 8 | #include "core/hle/ipc_helpers.h" | ||
| 9 | #include "core/hle/kernel/process.h" | ||
| 7 | #include "core/hle/service/ldr/ldr.h" | 10 | #include "core/hle/service/ldr/ldr.h" |
| 8 | #include "core/hle/service/service.h" | 11 | #include "core/hle/service/service.h" |
| 12 | #include "core/loader/nro.h" | ||
| 9 | 13 | ||
| 10 | namespace Service::LDR { | 14 | namespace Service::LDR { |
| 11 | 15 | ||
| @@ -59,16 +63,58 @@ public: | |||
| 59 | explicit RelocatableObject() : ServiceFramework{"ldr:ro"} { | 63 | explicit RelocatableObject() : ServiceFramework{"ldr:ro"} { |
| 60 | // clang-format off | 64 | // clang-format off |
| 61 | static const FunctionInfo functions[] = { | 65 | static const FunctionInfo functions[] = { |
| 62 | {0, nullptr, "LoadNro"}, | 66 | {0, &RelocatableObject::LoadNro, "LoadNro"}, |
| 63 | {1, nullptr, "UnloadNro"}, | 67 | {1, nullptr, "UnloadNro"}, |
| 64 | {2, nullptr, "LoadNrr"}, | 68 | {2, &RelocatableObject::LoadNrr, "LoadNrr"}, |
| 65 | {3, nullptr, "UnloadNrr"}, | 69 | {3, nullptr, "UnloadNrr"}, |
| 66 | {4, nullptr, "Initialize"}, | 70 | {4, &RelocatableObject::Initialize, "Initialize"}, |
| 67 | }; | 71 | }; |
| 68 | // clang-format on | 72 | // clang-format on |
| 69 | 73 | ||
| 70 | RegisterHandlers(functions); | 74 | RegisterHandlers(functions); |
| 71 | } | 75 | } |
| 76 | |||
| 77 | void LoadNrr(Kernel::HLERequestContext& ctx) { | ||
| 78 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 79 | rb.Push(RESULT_SUCCESS); | ||
| 80 | LOG_WARNING(Service_LDR, "(STUBBED) called"); | ||
| 81 | } | ||
| 82 | |||
| 83 | void LoadNro(Kernel::HLERequestContext& ctx) { | ||
| 84 | IPC::RequestParser rp{ctx}; | ||
| 85 | rp.Skip(2, false); | ||
| 86 | const VAddr nro_addr{rp.Pop<VAddr>()}; | ||
| 87 | const u64 nro_size{rp.Pop<u64>()}; | ||
| 88 | const VAddr bss_addr{rp.Pop<VAddr>()}; | ||
| 89 | const u64 bss_size{rp.Pop<u64>()}; | ||
| 90 | |||
| 91 | // Read NRO data from memory | ||
| 92 | std::vector<u8> nro_data(nro_size); | ||
| 93 | Memory::ReadBlock(nro_addr, nro_data.data(), nro_size); | ||
| 94 | |||
| 95 | // Load NRO as new executable module | ||
| 96 | const VAddr addr{*Core::CurrentProcess()->VMManager().FindFreeRegion(nro_size + bss_size)}; | ||
| 97 | Loader::AppLoader_NRO::LoadNro(nro_data, fmt::format("nro-{:08x}", addr), addr); | ||
| 98 | |||
| 99 | // TODO(bunnei): This is an incomplete implementation. It was tested with Super Mario Party. | ||
| 100 | // It is currently missing: | ||
| 101 | // - Signature checks with LoadNRR | ||
| 102 | // - Checking if a module has already been loaded | ||
| 103 | // - Using/validating BSS, etc. params (these are used from NRO header instead) | ||
| 104 | // - Error checking | ||
| 105 | // - ...Probably other things | ||
| 106 | |||
| 107 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 108 | rb.Push(RESULT_SUCCESS); | ||
| 109 | rb.Push(addr); | ||
| 110 | LOG_WARNING(Service_LDR, "(STUBBED) called"); | ||
| 111 | } | ||
| 112 | |||
| 113 | void Initialize(Kernel::HLERequestContext& ctx) { | ||
| 114 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 115 | rb.Push(RESULT_SUCCESS); | ||
| 116 | LOG_WARNING(Service_LDR, "(STUBBED) called"); | ||
| 117 | } | ||
| 72 | }; | 118 | }; |
| 73 | 119 | ||
| 74 | void InstallInterfaces(SM::ServiceManager& sm) { | 120 | void InstallInterfaces(SM::ServiceManager& sm) { |
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp index 9a4eb9301..c1af878fe 100644 --- a/src/core/hle/service/nfp/nfp.cpp +++ b/src/core/hle/service/nfp/nfp.cpp | |||
| @@ -328,13 +328,15 @@ void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) { | |||
| 328 | rb.PushIpcInterface<IUser>(*this); | 328 | rb.PushIpcInterface<IUser>(*this); |
| 329 | } | 329 | } |
| 330 | 330 | ||
| 331 | void Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) { | 331 | bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) { |
| 332 | std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock); | 332 | std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock); |
| 333 | if (buffer.size() < sizeof(AmiiboFile)) { | 333 | if (buffer.size() < sizeof(AmiiboFile)) { |
| 334 | return; // Failed to load file | 334 | return false; |
| 335 | } | 335 | } |
| 336 | |||
| 336 | std::memcpy(&amiibo, buffer.data(), sizeof(amiibo)); | 337 | std::memcpy(&amiibo, buffer.data(), sizeof(amiibo)); |
| 337 | nfc_tag_load->Signal(); | 338 | nfc_tag_load->Signal(); |
| 339 | return true; | ||
| 338 | } | 340 | } |
| 339 | const Kernel::SharedPtr<Kernel::Event>& Module::Interface::GetNFCEvent() const { | 341 | const Kernel::SharedPtr<Kernel::Event>& Module::Interface::GetNFCEvent() const { |
| 340 | return nfc_tag_load; | 342 | return nfc_tag_load; |
diff --git a/src/core/hle/service/nfp/nfp.h b/src/core/hle/service/nfp/nfp.h index 46370dedd..5c0ae8a54 100644 --- a/src/core/hle/service/nfp/nfp.h +++ b/src/core/hle/service/nfp/nfp.h | |||
| @@ -32,7 +32,7 @@ public: | |||
| 32 | static_assert(sizeof(AmiiboFile) == 0x94, "AmiiboFile is an invalid size"); | 32 | static_assert(sizeof(AmiiboFile) == 0x94, "AmiiboFile is an invalid size"); |
| 33 | 33 | ||
| 34 | void CreateUserInterface(Kernel::HLERequestContext& ctx); | 34 | void CreateUserInterface(Kernel::HLERequestContext& ctx); |
| 35 | void LoadAmiibo(const std::vector<u8>& buffer); | 35 | bool LoadAmiibo(const std::vector<u8>& buffer); |
| 36 | const Kernel::SharedPtr<Kernel::Event>& GetNFCEvent() const; | 36 | const Kernel::SharedPtr<Kernel::Event>& GetNFCEvent() const; |
| 37 | const AmiiboFile& GetAmiiboBuffer() const; | 37 | const AmiiboFile& GetAmiiboBuffer() const; |
| 38 | 38 | ||
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index 243b499f2..bc8e402a8 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp | |||
| @@ -127,18 +127,23 @@ static constexpr u32 PageAlignSize(u32 size) { | |||
| 127 | return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK; | 127 | return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK; |
| 128 | } | 128 | } |
| 129 | 129 | ||
| 130 | bool AppLoader_NRO::LoadNro(const FileSys::VfsFile& file, VAddr load_base) { | 130 | /*static*/ bool AppLoader_NRO::LoadNro(const std::vector<u8>& data, const std::string& name, |
| 131 | // Read NSO header | 131 | VAddr load_base) { |
| 132 | NroHeader nro_header{}; | 132 | |
| 133 | if (sizeof(NroHeader) != file.ReadObject(&nro_header)) { | 133 | if (data.size() < sizeof(NroHeader)) { |
| 134 | return {}; | 134 | return {}; |
| 135 | } | 135 | } |
| 136 | |||
| 137 | // Read NSO header | ||
| 138 | NroHeader nro_header{}; | ||
| 139 | std::memcpy(&nro_header, data.data(), sizeof(NroHeader)); | ||
| 136 | if (nro_header.magic != Common::MakeMagic('N', 'R', 'O', '0')) { | 140 | if (nro_header.magic != Common::MakeMagic('N', 'R', 'O', '0')) { |
| 137 | return {}; | 141 | return {}; |
| 138 | } | 142 | } |
| 139 | 143 | ||
| 140 | // Build program image | 144 | // Build program image |
| 141 | std::vector<u8> program_image = file.ReadBytes(PageAlignSize(nro_header.file_size)); | 145 | std::vector<u8> program_image(PageAlignSize(nro_header.file_size)); |
| 146 | std::memcpy(program_image.data(), data.data(), program_image.size()); | ||
| 142 | if (program_image.size() != PageAlignSize(nro_header.file_size)) { | 147 | if (program_image.size() != PageAlignSize(nro_header.file_size)) { |
| 143 | return {}; | 148 | return {}; |
| 144 | } | 149 | } |
| @@ -182,11 +187,15 @@ bool AppLoader_NRO::LoadNro(const FileSys::VfsFile& file, VAddr load_base) { | |||
| 182 | Core::CurrentProcess()->LoadModule(std::move(codeset), load_base); | 187 | Core::CurrentProcess()->LoadModule(std::move(codeset), load_base); |
| 183 | 188 | ||
| 184 | // Register module with GDBStub | 189 | // Register module with GDBStub |
| 185 | GDBStub::RegisterModule(file.GetName(), load_base, load_base); | 190 | GDBStub::RegisterModule(name, load_base, load_base); |
| 186 | 191 | ||
| 187 | return true; | 192 | return true; |
| 188 | } | 193 | } |
| 189 | 194 | ||
| 195 | bool AppLoader_NRO::LoadNro(const FileSys::VfsFile& file, VAddr load_base) { | ||
| 196 | return AppLoader_NRO::LoadNro(file.ReadAllBytes(), file.GetName(), load_base); | ||
| 197 | } | ||
| 198 | |||
| 190 | ResultStatus AppLoader_NRO::Load(Kernel::Process& process) { | 199 | ResultStatus AppLoader_NRO::Load(Kernel::Process& process) { |
| 191 | if (is_loaded) { | 200 | if (is_loaded) { |
| 192 | return ResultStatus::ErrorAlreadyLoaded; | 201 | return ResultStatus::ErrorAlreadyLoaded; |
diff --git a/src/core/loader/nro.h b/src/core/loader/nro.h index 50ee5a78a..3e6959302 100644 --- a/src/core/loader/nro.h +++ b/src/core/loader/nro.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <string> | 7 | #include <string> |
| 8 | #include <vector> | ||
| 8 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 9 | #include "core/loader/linker.h" | 10 | #include "core/loader/linker.h" |
| 10 | #include "core/loader/loader.h" | 11 | #include "core/loader/loader.h" |
| @@ -40,6 +41,8 @@ public: | |||
| 40 | ResultStatus ReadTitle(std::string& title) override; | 41 | ResultStatus ReadTitle(std::string& title) override; |
| 41 | bool IsRomFSUpdatable() const override; | 42 | bool IsRomFSUpdatable() const override; |
| 42 | 43 | ||
| 44 | static bool LoadNro(const std::vector<u8>& data, const std::string& name, VAddr load_base); | ||
| 45 | |||
| 43 | private: | 46 | private: |
| 44 | bool LoadNro(const FileSys::VfsFile& file, VAddr load_base); | 47 | bool LoadNro(const FileSys::VfsFile& file, VAddr load_base); |
| 45 | 48 | ||
diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp index 0bc307e99..20ffb0a9a 100644 --- a/src/yuzu/configuration/configure_system.cpp +++ b/src/yuzu/configuration/configure_system.cpp | |||
| @@ -21,12 +21,8 @@ | |||
| 21 | #include "yuzu/configuration/configure_system.h" | 21 | #include "yuzu/configuration/configure_system.h" |
| 22 | #include "yuzu/main.h" | 22 | #include "yuzu/main.h" |
| 23 | 23 | ||
| 24 | static std::string GetImagePath(Service::Account::UUID uuid) { | 24 | namespace { |
| 25 | return FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + | 25 | constexpr std::array<int, 12> days_in_month = {{ |
| 26 | "/system/save/8000000000000010/su/avators/" + uuid.FormatSwitch() + ".jpg"; | ||
| 27 | } | ||
| 28 | |||
| 29 | static const std::array<int, 12> days_in_month = {{ | ||
| 30 | 31, | 26 | 31, |
| 31 | 29, | 27 | 29, |
| 32 | 31, | 28 | 31, |
| @@ -42,7 +38,7 @@ static const std::array<int, 12> days_in_month = {{ | |||
| 42 | }}; | 38 | }}; |
| 43 | 39 | ||
| 44 | // Same backup JPEG used by acc IProfile::GetImage if no jpeg found | 40 | // Same backup JPEG used by acc IProfile::GetImage if no jpeg found |
| 45 | static constexpr std::array<u8, 107> backup_jpeg{ | 41 | constexpr std::array<u8, 107> backup_jpeg{ |
| 46 | 0xff, 0xd8, 0xff, 0xdb, 0x00, 0x43, 0x00, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x02, 0x02, | 42 | 0xff, 0xd8, 0xff, 0xdb, 0x00, 0x43, 0x00, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x02, 0x02, |
| 47 | 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x06, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x06, 0x06, 0x05, | 43 | 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x06, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x06, 0x06, 0x05, |
| 48 | 0x06, 0x09, 0x08, 0x0a, 0x0a, 0x09, 0x08, 0x09, 0x09, 0x0a, 0x0c, 0x0f, 0x0c, 0x0a, 0x0b, 0x0e, | 44 | 0x06, 0x09, 0x08, 0x0a, 0x0a, 0x09, 0x08, 0x09, 0x09, 0x0a, 0x0c, 0x0f, 0x0c, 0x0a, 0x0b, 0x0e, |
| @@ -52,15 +48,32 @@ static constexpr std::array<u8, 107> backup_jpeg{ | |||
| 52 | 0x01, 0x01, 0x00, 0x00, 0x3f, 0x00, 0xd2, 0xcf, 0x20, 0xff, 0xd9, | 48 | 0x01, 0x01, 0x00, 0x00, 0x3f, 0x00, 0xd2, 0xcf, 0x20, 0xff, 0xd9, |
| 53 | }; | 49 | }; |
| 54 | 50 | ||
| 51 | std::string GetImagePath(Service::Account::UUID uuid) { | ||
| 52 | return FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + | ||
| 53 | "/system/save/8000000000000010/su/avators/" + uuid.FormatSwitch() + ".jpg"; | ||
| 54 | } | ||
| 55 | |||
| 56 | std::string GetAccountUsername(const Service::Account::ProfileManager& manager, | ||
| 57 | Service::Account::UUID uuid) { | ||
| 58 | Service::Account::ProfileBase profile; | ||
| 59 | if (!manager.GetProfileBase(uuid, profile)) { | ||
| 60 | return ""; | ||
| 61 | } | ||
| 62 | |||
| 63 | return Common::StringFromFixedZeroTerminatedBuffer( | ||
| 64 | reinterpret_cast<const char*>(profile.username.data()), profile.username.size()); | ||
| 65 | } | ||
| 66 | } // Anonymous namespace | ||
| 67 | |||
| 55 | ConfigureSystem::ConfigureSystem(QWidget* parent) | 68 | ConfigureSystem::ConfigureSystem(QWidget* parent) |
| 56 | : QWidget(parent), ui(new Ui::ConfigureSystem), | 69 | : QWidget(parent), ui(new Ui::ConfigureSystem), |
| 57 | profile_manager(std::make_unique<Service::Account::ProfileManager>()) { | 70 | profile_manager(std::make_unique<Service::Account::ProfileManager>()) { |
| 58 | ui->setupUi(this); | 71 | ui->setupUi(this); |
| 59 | connect(ui->combo_birthmonth, | 72 | connect(ui->combo_birthmonth, |
| 60 | static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, | 73 | static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, |
| 61 | &ConfigureSystem::updateBirthdayComboBox); | 74 | &ConfigureSystem::UpdateBirthdayComboBox); |
| 62 | connect(ui->button_regenerate_console_id, &QPushButton::clicked, this, | 75 | connect(ui->button_regenerate_console_id, &QPushButton::clicked, this, |
| 63 | &ConfigureSystem::refreshConsoleID); | 76 | &ConfigureSystem::RefreshConsoleID); |
| 64 | 77 | ||
| 65 | layout = new QVBoxLayout; | 78 | layout = new QVBoxLayout; |
| 66 | tree_view = new QTreeView; | 79 | tree_view = new QTreeView; |
| @@ -154,7 +167,7 @@ void ConfigureSystem::UpdateCurrentUser() { | |||
| 154 | 167 | ||
| 155 | const auto& current_user = profile_manager->GetUser(Settings::values.current_user); | 168 | const auto& current_user = profile_manager->GetUser(Settings::values.current_user); |
| 156 | ASSERT(current_user != std::nullopt); | 169 | ASSERT(current_user != std::nullopt); |
| 157 | const auto username = GetAccountUsername(*current_user); | 170 | const auto username = GetAccountUsername(*profile_manager, *current_user); |
| 158 | 171 | ||
| 159 | scene->clear(); | 172 | scene->clear(); |
| 160 | scene->addPixmap( | 173 | scene->addPixmap( |
| @@ -164,14 +177,6 @@ void ConfigureSystem::UpdateCurrentUser() { | |||
| 164 | 177 | ||
| 165 | void ConfigureSystem::ReadSystemSettings() {} | 178 | void ConfigureSystem::ReadSystemSettings() {} |
| 166 | 179 | ||
| 167 | std::string ConfigureSystem::GetAccountUsername(Service::Account::UUID uuid) const { | ||
| 168 | Service::Account::ProfileBase profile; | ||
| 169 | if (!profile_manager->GetProfileBase(uuid, profile)) | ||
| 170 | return ""; | ||
| 171 | return Common::StringFromFixedZeroTerminatedBuffer( | ||
| 172 | reinterpret_cast<const char*>(profile.username.data()), profile.username.size()); | ||
| 173 | } | ||
| 174 | |||
| 175 | void ConfigureSystem::applyConfiguration() { | 180 | void ConfigureSystem::applyConfiguration() { |
| 176 | if (!enabled) | 181 | if (!enabled) |
| 177 | return; | 182 | return; |
| @@ -180,7 +185,7 @@ void ConfigureSystem::applyConfiguration() { | |||
| 180 | Settings::Apply(); | 185 | Settings::Apply(); |
| 181 | } | 186 | } |
| 182 | 187 | ||
| 183 | void ConfigureSystem::updateBirthdayComboBox(int birthmonth_index) { | 188 | void ConfigureSystem::UpdateBirthdayComboBox(int birthmonth_index) { |
| 184 | if (birthmonth_index < 0 || birthmonth_index >= 12) | 189 | if (birthmonth_index < 0 || birthmonth_index >= 12) |
| 185 | return; | 190 | return; |
| 186 | 191 | ||
| @@ -205,7 +210,7 @@ void ConfigureSystem::updateBirthdayComboBox(int birthmonth_index) { | |||
| 205 | ui->combo_birthday->setCurrentIndex(birthday_index); | 210 | ui->combo_birthday->setCurrentIndex(birthday_index); |
| 206 | } | 211 | } |
| 207 | 212 | ||
| 208 | void ConfigureSystem::refreshConsoleID() { | 213 | void ConfigureSystem::RefreshConsoleID() { |
| 209 | QMessageBox::StandardButton reply; | 214 | QMessageBox::StandardButton reply; |
| 210 | QString warning_text = tr("This will replace your current virtual Switch with a new one. " | 215 | QString warning_text = tr("This will replace your current virtual Switch with a new one. " |
| 211 | "Your current virtual Switch will not be recoverable. " | 216 | "Your current virtual Switch will not be recoverable. " |
| @@ -232,8 +237,7 @@ void ConfigureSystem::SelectUser(const QModelIndex& index) { | |||
| 232 | } | 237 | } |
| 233 | 238 | ||
| 234 | void ConfigureSystem::AddUser() { | 239 | void ConfigureSystem::AddUser() { |
| 235 | Service::Account::UUID uuid; | 240 | const auto uuid = Service::Account::UUID::Generate(); |
| 236 | uuid.Generate(); | ||
| 237 | 241 | ||
| 238 | bool ok = false; | 242 | bool ok = false; |
| 239 | const auto username = | 243 | const auto username = |
| @@ -253,7 +257,7 @@ void ConfigureSystem::RenameUser() { | |||
| 253 | const auto user = tree_view->currentIndex().row(); | 257 | const auto user = tree_view->currentIndex().row(); |
| 254 | const auto uuid = profile_manager->GetUser(user); | 258 | const auto uuid = profile_manager->GetUser(user); |
| 255 | ASSERT(uuid != std::nullopt); | 259 | ASSERT(uuid != std::nullopt); |
| 256 | const auto username = GetAccountUsername(*uuid); | 260 | const auto username = GetAccountUsername(*profile_manager, *uuid); |
| 257 | 261 | ||
| 258 | Service::Account::ProfileBase profile; | 262 | Service::Account::ProfileBase profile; |
| 259 | if (!profile_manager->GetProfileBase(*uuid, profile)) | 263 | if (!profile_manager->GetProfileBase(*uuid, profile)) |
| @@ -293,7 +297,7 @@ void ConfigureSystem::DeleteUser() { | |||
| 293 | const auto index = tree_view->currentIndex().row(); | 297 | const auto index = tree_view->currentIndex().row(); |
| 294 | const auto uuid = profile_manager->GetUser(index); | 298 | const auto uuid = profile_manager->GetUser(index); |
| 295 | ASSERT(uuid != std::nullopt); | 299 | ASSERT(uuid != std::nullopt); |
| 296 | const auto username = GetAccountUsername(*uuid); | 300 | const auto username = GetAccountUsername(*profile_manager, *uuid); |
| 297 | 301 | ||
| 298 | const auto confirm = | 302 | const auto confirm = |
| 299 | QMessageBox::question(this, tr("Confirm Delete"), | 303 | QMessageBox::question(this, tr("Confirm Delete"), |
| @@ -321,10 +325,10 @@ void ConfigureSystem::SetUserImage() { | |||
| 321 | const auto index = tree_view->currentIndex().row(); | 325 | const auto index = tree_view->currentIndex().row(); |
| 322 | const auto uuid = profile_manager->GetUser(index); | 326 | const auto uuid = profile_manager->GetUser(index); |
| 323 | ASSERT(uuid != std::nullopt); | 327 | ASSERT(uuid != std::nullopt); |
| 324 | const auto username = GetAccountUsername(*uuid); | 328 | const auto username = GetAccountUsername(*profile_manager, *uuid); |
| 325 | 329 | ||
| 326 | const auto file = QFileDialog::getOpenFileName(this, tr("Select User Image"), QString(), | 330 | const auto file = QFileDialog::getOpenFileName(this, tr("Select User Image"), QString(), |
| 327 | "JPEG Images (*.jpg *.jpeg)"); | 331 | tr("JPEG Images (*.jpg *.jpeg)")); |
| 328 | 332 | ||
| 329 | if (file.isEmpty()) | 333 | if (file.isEmpty()) |
| 330 | return; | 334 | return; |
diff --git a/src/yuzu/configuration/configure_system.h b/src/yuzu/configuration/configure_system.h index b73e0719c..07764e1f7 100644 --- a/src/yuzu/configuration/configure_system.h +++ b/src/yuzu/configuration/configure_system.h | |||
| @@ -9,17 +9,16 @@ | |||
| 9 | #include <QList> | 9 | #include <QList> |
| 10 | #include <QWidget> | 10 | #include <QWidget> |
| 11 | 11 | ||
| 12 | namespace Service::Account { | ||
| 13 | class ProfileManager; | ||
| 14 | struct UUID; | ||
| 15 | } // namespace Service::Account | ||
| 16 | |||
| 17 | class QGraphicsScene; | 12 | class QGraphicsScene; |
| 18 | class QStandardItem; | 13 | class QStandardItem; |
| 19 | class QStandardItemModel; | 14 | class QStandardItemModel; |
| 20 | class QTreeView; | 15 | class QTreeView; |
| 21 | class QVBoxLayout; | 16 | class QVBoxLayout; |
| 22 | 17 | ||
| 18 | namespace Service::Account { | ||
| 19 | class ProfileManager; | ||
| 20 | } | ||
| 21 | |||
| 23 | namespace Ui { | 22 | namespace Ui { |
| 24 | class ConfigureSystem; | 23 | class ConfigureSystem; |
| 25 | } | 24 | } |
| @@ -29,28 +28,25 @@ class ConfigureSystem : public QWidget { | |||
| 29 | 28 | ||
| 30 | public: | 29 | public: |
| 31 | explicit ConfigureSystem(QWidget* parent = nullptr); | 30 | explicit ConfigureSystem(QWidget* parent = nullptr); |
| 32 | ~ConfigureSystem(); | 31 | ~ConfigureSystem() override; |
| 33 | 32 | ||
| 34 | void applyConfiguration(); | 33 | void applyConfiguration(); |
| 35 | void setConfiguration(); | 34 | void setConfiguration(); |
| 36 | 35 | ||
| 37 | void PopulateUserList(); | 36 | private: |
| 38 | void UpdateCurrentUser(); | 37 | void ReadSystemSettings(); |
| 39 | 38 | ||
| 40 | public slots: | 39 | void UpdateBirthdayComboBox(int birthmonth_index); |
| 41 | void updateBirthdayComboBox(int birthmonth_index); | 40 | void RefreshConsoleID(); |
| 42 | void refreshConsoleID(); | ||
| 43 | 41 | ||
| 42 | void PopulateUserList(); | ||
| 43 | void UpdateCurrentUser(); | ||
| 44 | void SelectUser(const QModelIndex& index); | 44 | void SelectUser(const QModelIndex& index); |
| 45 | void AddUser(); | 45 | void AddUser(); |
| 46 | void RenameUser(); | 46 | void RenameUser(); |
| 47 | void DeleteUser(); | 47 | void DeleteUser(); |
| 48 | void SetUserImage(); | 48 | void SetUserImage(); |
| 49 | 49 | ||
| 50 | private: | ||
| 51 | void ReadSystemSettings(); | ||
| 52 | std::string GetAccountUsername(Service::Account::UUID uuid) const; | ||
| 53 | |||
| 54 | QVBoxLayout* layout; | 50 | QVBoxLayout* layout; |
| 55 | QTreeView* tree_view; | 51 | QTreeView* tree_view; |
| 56 | QStandardItemModel* item_model; | 52 | QStandardItemModel* item_model; |
| @@ -59,11 +55,12 @@ private: | |||
| 59 | std::vector<QList<QStandardItem*>> list_items; | 55 | std::vector<QList<QStandardItem*>> list_items; |
| 60 | 56 | ||
| 61 | std::unique_ptr<Ui::ConfigureSystem> ui; | 57 | std::unique_ptr<Ui::ConfigureSystem> ui; |
| 62 | bool enabled; | 58 | bool enabled = false; |
| 63 | 59 | ||
| 64 | int birthmonth, birthday; | 60 | int birthmonth = 0; |
| 65 | int language_index; | 61 | int birthday = 0; |
| 66 | int sound_index; | 62 | int language_index = 0; |
| 63 | int sound_index = 0; | ||
| 67 | 64 | ||
| 68 | std::unique_ptr<Service::Account::ProfileManager> profile_manager; | 65 | std::unique_ptr<Service::Account::ProfileManager> profile_manager; |
| 69 | }; | 66 | }; |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 55508b1e1..b5bfa6741 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -30,6 +30,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual | |||
| 30 | #define QT_NO_OPENGL | 30 | #define QT_NO_OPENGL |
| 31 | #include <QDesktopWidget> | 31 | #include <QDesktopWidget> |
| 32 | #include <QDialogButtonBox> | 32 | #include <QDialogButtonBox> |
| 33 | #include <QFile> | ||
| 33 | #include <QFileDialog> | 34 | #include <QFileDialog> |
| 34 | #include <QMessageBox> | 35 | #include <QMessageBox> |
| 35 | #include <QtConcurrent/QtConcurrent> | 36 | #include <QtConcurrent/QtConcurrent> |
| @@ -1336,20 +1337,40 @@ void GMainWindow::OnLoadAmiibo() { | |||
| 1336 | const QString extensions{"*.bin"}; | 1337 | const QString extensions{"*.bin"}; |
| 1337 | const QString file_filter = tr("Amiibo File (%1);; All Files (*.*)").arg(extensions); | 1338 | const QString file_filter = tr("Amiibo File (%1);; All Files (*.*)").arg(extensions); |
| 1338 | const QString filename = QFileDialog::getOpenFileName(this, tr("Load Amiibo"), "", file_filter); | 1339 | const QString filename = QFileDialog::getOpenFileName(this, tr("Load Amiibo"), "", file_filter); |
| 1339 | if (!filename.isEmpty()) { | 1340 | |
| 1340 | Core::System& system{Core::System::GetInstance()}; | 1341 | if (filename.isEmpty()) { |
| 1341 | Service::SM::ServiceManager& sm = system.ServiceManager(); | 1342 | return; |
| 1342 | auto nfc = sm.GetService<Service::NFP::Module::Interface>("nfp:user"); | 1343 | } |
| 1343 | if (nfc != nullptr) { | 1344 | |
| 1344 | auto nfc_file = FileUtil::IOFile(filename.toStdString(), "rb"); | 1345 | Core::System& system{Core::System::GetInstance()}; |
| 1345 | if (!nfc_file.IsOpen()) { | 1346 | Service::SM::ServiceManager& sm = system.ServiceManager(); |
| 1346 | return; | 1347 | auto nfc = sm.GetService<Service::NFP::Module::Interface>("nfp:user"); |
| 1347 | } | 1348 | if (nfc == nullptr) { |
| 1348 | std::vector<u8> amiibo_buffer(nfc_file.GetSize()); | 1349 | return; |
| 1349 | nfc_file.ReadBytes(amiibo_buffer.data(), amiibo_buffer.size()); | 1350 | } |
| 1350 | nfc_file.Close(); | 1351 | |
| 1351 | nfc->LoadAmiibo(amiibo_buffer); | 1352 | QFile nfc_file{filename}; |
| 1352 | } | 1353 | if (!nfc_file.open(QIODevice::ReadOnly)) { |
| 1354 | QMessageBox::warning(this, tr("Error opening Amiibo data file"), | ||
| 1355 | tr("Unable to open Amiibo file \"%1\" for reading.").arg(filename)); | ||
| 1356 | return; | ||
| 1357 | } | ||
| 1358 | |||
| 1359 | const u64 nfc_file_size = nfc_file.size(); | ||
| 1360 | std::vector<u8> buffer(nfc_file_size); | ||
| 1361 | const u64 read_size = nfc_file.read(reinterpret_cast<char*>(buffer.data()), nfc_file_size); | ||
| 1362 | if (nfc_file_size != read_size) { | ||
| 1363 | QMessageBox::warning(this, tr("Error reading Amiibo data file"), | ||
| 1364 | tr("Unable to fully read Amiibo data. Expected to read %1 bytes, but " | ||
| 1365 | "was only able to read %2 bytes.") | ||
| 1366 | .arg(nfc_file_size) | ||
| 1367 | .arg(read_size)); | ||
| 1368 | return; | ||
| 1369 | } | ||
| 1370 | |||
| 1371 | if (!nfc->LoadAmiibo(buffer)) { | ||
| 1372 | QMessageBox::warning(this, tr("Error loading Amiibo data"), | ||
| 1373 | tr("Unable to load Amiibo data.")); | ||
| 1353 | } | 1374 | } |
| 1354 | } | 1375 | } |
| 1355 | 1376 | ||