From a41fc74dba18235935aff924e9d04b2b026ee5d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 1 May 2023 11:41:25 +0200 Subject: [PATCH 1/8] Add a debug assert in VulkanPushPool --- Common/GPU/Vulkan/VulkanMemory.cpp | 2 ++ Common/GPU/Vulkan/VulkanMemory.h | 1 + 2 files changed, 3 insertions(+) diff --git a/Common/GPU/Vulkan/VulkanMemory.cpp b/Common/GPU/Vulkan/VulkanMemory.cpp index 3d65980912..06c834dd4c 100644 --- a/Common/GPU/Vulkan/VulkanMemory.cpp +++ b/Common/GPU/Vulkan/VulkanMemory.cpp @@ -372,6 +372,8 @@ void VulkanPushPool::BeginFrame() { } void VulkanPushPool::NextBlock(VkDeviceSize allocationSize) { + _dbg_assert_(allocationSize != 0); // If so, the logic in the caller is wrong, should never need a new block for this case. + int curFrameIndex = vulkan_->GetCurFrame(); curBlockIndex_++; while (curBlockIndex_ < blocks_.size()) { diff --git a/Common/GPU/Vulkan/VulkanMemory.h b/Common/GPU/Vulkan/VulkanMemory.h index f4d502e138..151c31ab60 100644 --- a/Common/GPU/Vulkan/VulkanMemory.h +++ b/Common/GPU/Vulkan/VulkanMemory.h @@ -121,6 +121,7 @@ public: void GetDebugString(char *buffer, size_t bufSize) const override; // When using the returned memory, make sure to bind the returned vkbuf. + // It is okay to allocate 0 bytes. uint8_t *Allocate(VkDeviceSize numBytes, VkDeviceSize alignment, VkBuffer *vkbuf, uint32_t *bindOffset) { _dbg_assert_(curBlockIndex_ >= 0); From d4249c1d73b30b8be7b2394c54c0ed27928eae0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 1 May 2023 11:56:26 +0200 Subject: [PATCH 2/8] OpenGL: Add an assert to catch a class of crash bugs early. Also assorted paranoia. --- Common/GPU/OpenGL/GLRenderManager.h | 4 ++++ Common/GPU/Vulkan/thin3d_vulkan.cpp | 5 +++++ GPU/GLES/DrawEngineGLES.cpp | 3 +++ UI/MiscScreens.cpp | 1 + 4 files changed, 13 insertions(+) diff --git a/Common/GPU/OpenGL/GLRenderManager.h b/Common/GPU/OpenGL/GLRenderManager.h index 3c9fdfd1f5..07f54ffab4 100644 --- a/Common/GPU/OpenGL/GLRenderManager.h +++ b/Common/GPU/OpenGL/GLRenderManager.h @@ -532,6 +532,10 @@ public: pushbuffer->End(); } + bool IsInRenderPass() const { + return curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER; + } + // This starts a new step (like a "render pass" in Vulkan). // // After a "CopyFramebuffer" or the other functions that start "steps", you need to call this before diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index 351fa38faf..648a21875e 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -1487,6 +1487,11 @@ void VKContext::DrawIndexed(int vertexCount, int offset) { } void VKContext::DrawUP(const void *vdata, int vertexCount) { + _dbg_assert_(vertexCount >= 0); + if (vertexCount <= 0) { + return; + } + VkBuffer vulkanVbuf, vulkanUBObuf; size_t vbBindOffset = push_->Push(vdata, vertexCount * curPipeline_->stride[0], 4, &vulkanVbuf); uint32_t ubo_offset = (uint32_t)curPipeline_->PushUBO(push_, vulkan_, &vulkanUBObuf); diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index 193b8ab67f..1db3fabde1 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -250,6 +250,9 @@ void DrawEngineGLES::DoFlush() { PROFILE_THIS_SCOPE("flush"); FrameData &frameData = frameData_[render_->GetCurFrame()]; + // Attempt to gather some information (asserts now upload the game name). + _assert_(render_->IsInRenderPass()); + bool textureNeedsApply = false; if (gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS) && !gstate.isModeClear() && gstate.isTextureMapEnabled()) { textureCache_->SetTexture(); diff --git a/UI/MiscScreens.cpp b/UI/MiscScreens.cpp index e1483d0a20..fdfcb6529c 100644 --- a/UI/MiscScreens.cpp +++ b/UI/MiscScreens.cpp @@ -171,6 +171,7 @@ public: int n = i & 3; ui_draw2d.DrawImageRotated(symbols[n], x, y, 1.0f, angle, colorAlpha(colors[n], alpha * 0.1f)); } + dc.Flush(); } private: From c1ede07a145b2837d5abbe6f6aaaa67bf48d9d40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 1 May 2023 12:02:41 +0200 Subject: [PATCH 3/8] Add missing JNI context to reporting thread --- Core/Reporting.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Core/Reporting.cpp b/Core/Reporting.cpp index 946285dfea..bedcbf8d85 100644 --- a/Core/Reporting.cpp +++ b/Core/Reporting.cpp @@ -480,6 +480,8 @@ namespace Reporting { SetCurrentThreadName("Report"); + AndroidJNIThreadContext jniContext; // destructor detaches + Payload &payload = payloadBuffer[pos]; Buffer output; From 7c420381d5625df7a584bc8386aeff7ebdd1b35f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 1 May 2023 12:11:34 +0200 Subject: [PATCH 4/8] OpenGL: Some paranoia checks around failed shader generation --- GPU/GLES/DrawEngineGLES.cpp | 7 ++++++- GPU/GLES/ShaderManagerGLES.cpp | 9 ++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index 1db3fabde1..b191014219 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -414,7 +414,11 @@ void DrawEngineGLES::DoFlush() { ApplyDrawStateLate(result.setStencil, result.stencilValue); - shaderManager_->ApplyFragmentShader(vsid, vshader, pipelineState_, framebufferManager_->UseBufferedRendering()); + LinkedShader *linked = shaderManager_->ApplyFragmentShader(vsid, vshader, pipelineState_, framebufferManager_->UseBufferedRendering()); + if (!linked) { + // Not much we can do here. Let's skip drawing. + goto bail; + } if (result.action == SW_DRAW_PRIMITIVES) { if (result.drawIndexed) { @@ -458,6 +462,7 @@ void DrawEngineGLES::DoFlush() { decOptions_.applySkinInDecode = g_Config.bSoftwareSkinning; } +bail: gpuStats.numFlushes++; gpuStats.numDrawCalls += numDrawCalls; gpuStats.numVertsSubmitted += vertexCountInDrawCalls_; diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index 7718eedcbb..22669a0392 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -76,13 +76,15 @@ LinkedShader::LinkedShader(GLRenderManager *render, VShaderID VSID, Shader *vs, : render_(render), useHWTransform_(useHWTransform) { PROFILE_THIS_SCOPE("shaderlink"); + _assert_(vs); + _assert_(fs); + vs_ = vs; std::vector shaders; shaders.push_back(vs->shader); shaders.push_back(fs->shader); - std::vector semantics; semantics.reserve(7); semantics.push_back({ ATTR_POSITION, "position" }); @@ -874,6 +876,11 @@ LinkedShader *ShaderManagerGLES::ApplyFragmentShader(VShaderID VSID, Shader *vs, if (ls == nullptr) { _dbg_assert_(FSID.Bit(FS_BIT_FLATSHADE) == VSID.Bit(VS_BIT_FLATSHADE)); + if (vs == nullptr || fs == nullptr) { + // Can't draw. This shouldn't really happen. + return nullptr; + } + // Check if we can link these. ls = new LinkedShader(render_, VSID, vs, FSID, fs, vs->UseHWTransform()); ls->use(VSID); From 15a0474d4087039408d208b109e85beccaf5b3d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 1 May 2023 12:16:45 +0200 Subject: [PATCH 5/8] NativeKey: Only update the HLEPlugins key map if any plugins are active. --- Core/HLE/Plugins.cpp | 9 ++++++++- Core/HLE/Plugins.h | 6 +++++- UI/NativeApp.cpp | 8 ++++---- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/Core/HLE/Plugins.cpp b/Core/HLE/Plugins.cpp index 202fdda331..044d926b05 100644 --- a/Core/HLE/Plugins.cpp +++ b/Core/HLE/Plugins.cpp @@ -29,6 +29,7 @@ #include "Core/HLE/sceKernelModule.h" namespace HLEPlugins { + float PluginDataAxis[JOYSTICK_AXIS_MAX]; std::map PluginDataKeys; @@ -214,4 +215,10 @@ bool HasEnabled() { return anyEnabled; } -}; +void SetKey(int key, uint8_t value) { + if (anyEnabled) { + PluginDataKeys[key] = value; + } +} + +} // namespace diff --git a/Core/HLE/Plugins.h b/Core/HLE/Plugins.h index 7503d01cb0..bef0494536 100644 --- a/Core/HLE/Plugins.h +++ b/Core/HLE/Plugins.h @@ -17,6 +17,7 @@ #pragma once +#include #include "Input/KeyCodes.h" class PointerWrap; @@ -33,6 +34,9 @@ void DoState(PointerWrap &p); bool HasEnabled(); +void SetKey(int key, uint8_t value); + extern float PluginDataAxis[JOYSTICK_AXIS_MAX]; extern std::map PluginDataKeys; -}; + +} // namespace diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index e1f858c2c3..1985583e5d 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -1257,7 +1257,7 @@ bool NativeKey(const KeyInput &key) { // INFO_LOG(SYSTEM, "Key code: %i flags: %i", key.keyCode, key.flags); #if !defined(MOBILE_DEVICE) if (g_Config.bPauseExitsEmulator) { - static std::vector pspKeys; + std::vector pspKeys; pspKeys.clear(); if (KeyMap::InputMappingToPspButton(InputMapping(key.deviceId, key.keyCode), &pspKeys)) { if (std::find(pspKeys.begin(), pspKeys.end(), VIRTKEY_PAUSE) != pspKeys.end()) { @@ -1267,10 +1267,10 @@ bool NativeKey(const KeyInput &key) { } } #endif + bool retval = false; - if (g_screenManager) - { - HLEPlugins::PluginDataKeys[key.keyCode] = (key.flags & KEY_DOWN) ? 1 : 0; + if (g_screenManager) { + HLEPlugins::SetKey(key.keyCode, (key.flags & KEY_DOWN) ? 1 : 0); retval = g_screenManager->key(key); } From 2c35c351f28fe301063fcb267dd04d6cf1b14e75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 1 May 2023 12:55:50 +0200 Subject: [PATCH 6/8] Lock around plugin key data, don't set it unless a plugin is enabled --- Core/HLE/Plugins.cpp | 12 ++++++++++++ Core/HLE/Plugins.h | 2 +- Core/HLE/sceIo.cpp | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Core/HLE/Plugins.cpp b/Core/HLE/Plugins.cpp index 044d926b05..0f5b682a92 100644 --- a/Core/HLE/Plugins.cpp +++ b/Core/HLE/Plugins.cpp @@ -16,6 +16,7 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include +#include #include "Common/Data/Format/IniFile.h" #include "Common/File/FileUtil.h" @@ -30,6 +31,7 @@ namespace HLEPlugins { +std::mutex g_inputMutex; float PluginDataAxis[JOYSTICK_AXIS_MAX]; std::map PluginDataKeys; @@ -190,6 +192,8 @@ bool Load() { started = true; } + std::lock_guard guard(g_inputMutex); + PluginDataKeys.clear(); return started; } @@ -200,6 +204,8 @@ void Unload() { void Shutdown() { prxPlugins.clear(); anyEnabled = false; + std::lock_guard guard(g_inputMutex); + PluginDataKeys.clear(); } void DoState(PointerWrap &p) { @@ -217,8 +223,14 @@ bool HasEnabled() { void SetKey(int key, uint8_t value) { if (anyEnabled) { + std::lock_guard guard(g_inputMutex); PluginDataKeys[key] = value; } } +uint8_t GetKey(int key) { + std::lock_guard guard(g_inputMutex); + return PluginDataKeys[key]; +} + } // namespace diff --git a/Core/HLE/Plugins.h b/Core/HLE/Plugins.h index bef0494536..3b5a2bd029 100644 --- a/Core/HLE/Plugins.h +++ b/Core/HLE/Plugins.h @@ -35,8 +35,8 @@ void DoState(PointerWrap &p); bool HasEnabled(); void SetKey(int key, uint8_t value); +uint8_t GetKey(int key); extern float PluginDataAxis[JOYSTICK_AXIS_MAX]; -extern std::map PluginDataKeys; } // namespace diff --git a/Core/HLE/sceIo.cpp b/Core/HLE/sceIo.cpp index 59db5a6923..d1d83ba453 100644 --- a/Core/HLE/sceIo.cpp +++ b/Core/HLE/sceIo.cpp @@ -2072,7 +2072,7 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o return 0; case EMULATOR_DEVCTL__GET_VKEY: if (Memory::IsValidAddress(outPtr) && (argAddr >= 0 && argAddr < NKCODE_MAX)) { - Memory::Write_U8(HLEPlugins::PluginDataKeys[argAddr], outPtr); + Memory::Write_U8(HLEPlugins::GetKey(argAddr), outPtr); } return 0; } From a43bdd81690d0297dc8fe95100bc66a0d83fc05a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 1 May 2023 13:48:04 +0200 Subject: [PATCH 7/8] ReadSFO: Fix memory safety issues --- Core/CoreTiming.cpp | 2 +- Core/ELF/ParamSFO.cpp | 71 +++++++++++++++++++++++++++++-------------- Core/ELF/ParamSFO.h | 14 ++++----- 3 files changed, 57 insertions(+), 30 deletions(-) diff --git a/Core/CoreTiming.cpp b/Core/CoreTiming.cpp index b832b4b74e..afa762e401 100644 --- a/Core/CoreTiming.cpp +++ b/Core/CoreTiming.cpp @@ -246,7 +246,7 @@ void Shutdown() delete ev; } } - + u64 GetTicks() { if (currentMIPS) { diff --git a/Core/ELF/ParamSFO.cpp b/Core/ELF/ParamSFO.cpp index a2c002f46e..6d05d88140 100644 --- a/Core/ELF/ParamSFO.cpp +++ b/Core/ELF/ParamSFO.cpp @@ -54,26 +54,28 @@ void ParamSFOData::SetValue(std::string key, std::string value, int max_size) { values[key].max_size = max_size; } -void ParamSFOData::SetValue(std::string key, const u8* value, unsigned int size, int max_size) { +void ParamSFOData::SetValue(std::string key, const u8 *value, unsigned int size, int max_size) { values[key].type = VT_UTF8_SPE; - values[key].SetData(value,size); + values[key].SetData(value, size); values[key].max_size = max_size; } -int ParamSFOData::GetValueInt(std::string key) { - std::map::iterator it = values.find(key); +int ParamSFOData::GetValueInt(std::string key) const { + std::map::const_iterator it = values.find(key); if(it == values.end() || it->second.type != VT_INT) return 0; return it->second.i_value; } -std::string ParamSFOData::GetValueString(std::string key) { - std::map::iterator it = values.find(key); + +std::string ParamSFOData::GetValueString(std::string key) const { + std::map::const_iterator it = values.find(key); if(it == values.end() || (it->second.type != VT_UTF8)) return ""; return it->second.s_value; } -u8* ParamSFOData::GetValueData(std::string key, unsigned int *size) { - std::map::iterator it = values.find(key); + +const u8 *ParamSFOData::GetValueData(std::string key, unsigned int *size) const { + std::map::const_iterator it = values.find(key); if(it == values.end() || (it->second.type != VT_UTF8_SPE)) return 0; if(size) @@ -83,7 +85,7 @@ u8* ParamSFOData::GetValueData(std::string key, unsigned int *size) { return it->second.u_value; } -std::vector ParamSFOData::GetKeys() { +std::vector ParamSFOData::GetKeys() const { std::vector result; for (const auto &pair : values) { result.push_back(pair.first); @@ -109,43 +111,70 @@ bool ParamSFOData::ReadSFO(const u8 *paramsfo, size_t size) { const u8 *data_start = paramsfo + header->data_table_start; + auto readStringCapped = [paramsfo, size](size_t offset, size_t maxLen) -> std::string { + std::string str; + while (offset < size) { + char c = (char)(paramsfo[offset]); + if (c) { + str.push_back(c); + } else { + break; + } + offset++; + if (maxLen != 0 && str.size() == maxLen) + break; + } + return str; + }; + for (u32 i = 0; i < header->index_table_entries; i++) { size_t key_offset = header->key_table_start + indexTables[i].key_table_offset; if (key_offset >= size) { return false; } + size_t data_offset = header->data_table_start + indexTables[i].data_table_offset; if (data_offset >= size) { return false; } - const char *key = (const char *)(paramsfo + key_offset); + std::string key = readStringCapped(key_offset, 0); + if (key.empty()) + continue; // Likely ran into a truncated PARAMSFO. + switch (indexTables[i].param_fmt) { case 0x0404: { + if (data_offset + 4 > size) + continue; // Unsigned int const u32_le *data = (const u32_le *)(paramsfo + data_offset); SetValue(key, *data, indexTables[i].param_max_len); - VERBOSE_LOG(LOADER, "%s %08x", key, *data); + VERBOSE_LOG(LOADER, "%s %08x", key.c_str(), *data); } break; case 0x0004: // Special format UTF-8 { + if (data_offset + indexTables[i].param_len > size) + continue; const u8 *utfdata = (const u8 *)(paramsfo + data_offset); - VERBOSE_LOG(LOADER, "%s %s", key, utfdata); + VERBOSE_LOG(LOADER, "%s %s", key.c_str(), utfdata); SetValue(key, utfdata, indexTables[i].param_len, indexTables[i].param_max_len); } break; case 0x0204: // Regular UTF-8 { - const char *utfdata = (const char *)(paramsfo + data_offset); - VERBOSE_LOG(LOADER, "%s %s", key, utfdata); - SetValue(key, std::string(utfdata /*, indexTables[i].param_len*/), indexTables[i].param_max_len); + // TODO: Likely should use param_len here, but there's gotta be a reason we avoided it before. + std::string str = readStringCapped(data_offset, indexTables[i].param_max_len); + VERBOSE_LOG(LOADER, "%s %s", key.c_str(), str.c_str()); + SetValue(key, str, indexTables[i].param_max_len); } break; + default: + break; } } @@ -176,7 +205,7 @@ int ParamSFOData::GetDataOffset(const u8 *paramsfo, std::string dataName) { return -1; } -bool ParamSFOData::WriteSFO(u8 **paramsfo, size_t *size) { +bool ParamSFOData::WriteSFO(u8 **paramsfo, size_t *size) const { size_t total_size = 0; size_t key_size = 0; size_t data_size = 0; @@ -198,7 +227,7 @@ bool ParamSFOData::WriteSFO(u8 **paramsfo, size_t *size) { } // Padding - while((key_size%4)) key_size++; + while ((key_size % 4) != 0) key_size++; header.key_table_start = sizeof(Header) + header.index_table_entries * sizeof(IndexTable); header.data_table_start = header.key_table_start + (u32)key_size; @@ -266,20 +295,18 @@ void ParamSFOData::Clear() { } void ParamSFOData::ValueData::SetData(const u8* data, int size) { - if(u_value) - { + if (u_value) { delete[] u_value; u_value = 0; } - if(size > 0) - { + if (size > 0) { u_value = new u8[size]; memcpy(u_value, data, size); } u_size = size; } -std::string ParamSFOData::GenerateFakeID(std::string filename) { +std::string ParamSFOData::GenerateFakeID(std::string filename) const { // Generates fake gameID for homebrew based on it's folder name. // Should probably not be a part of ParamSFO, but it'll be called in same places. std::string file = PSP_CoreParameter().fileToStart.ToString(); diff --git a/Core/ELF/ParamSFO.h b/Core/ELF/ParamSFO.h index 6548638ef6..e0bb48ec98 100644 --- a/Core/ELF/ParamSFO.h +++ b/Core/ELF/ParamSFO.h @@ -29,14 +29,14 @@ class ParamSFOData public: void SetValue(std::string key, unsigned int value, int max_size); void SetValue(std::string key, std::string value, int max_size); - void SetValue(std::string key, const u8* value, unsigned int size, int max_size); + void SetValue(std::string key, const u8 *value, unsigned int size, int max_size); - int GetValueInt(std::string key); - std::string GetValueString(std::string key); - u8* GetValueData(std::string key, unsigned int *size); + int GetValueInt(std::string key) const; + std::string GetValueString(std::string key) const; + const u8 *GetValueData(std::string key, unsigned int *size) const; - std::vector GetKeys(); - std::string GenerateFakeID(std::string filename = ""); + std::vector GetKeys() const; + std::string GenerateFakeID(std::string filename = "") const; std::string GetDiscID() { const std::string discID = GetValueString("DISC_ID"); @@ -53,7 +53,7 @@ public: } bool ReadSFO(const u8 *paramsfo, size_t size); - bool WriteSFO(u8 **paramsfo, size_t *size); + bool WriteSFO(u8 **paramsfo, size_t *size) const; bool ReadSFO(const std::vector ¶msfo) { if (!paramsfo.empty()) { From 646831959929c1cb0da07701d80118bbdaae8946 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 1 May 2023 13:56:35 +0200 Subject: [PATCH 8/8] Fix memory bug in memstick file copy routine --- UI/MemStickScreen.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/UI/MemStickScreen.cpp b/UI/MemStickScreen.cpp index 7e118cfbb6..8aad6a820a 100644 --- a/UI/MemStickScreen.cpp +++ b/UI/MemStickScreen.cpp @@ -633,18 +633,16 @@ void ConfirmMemstickMoveScreen::update() { } UI::EventReturn ConfirmMemstickMoveScreen::OnConfirm(UI::EventParams ¶ms) { - auto sy = GetI18NCategory(I18NCat::SYSTEM); - auto iz = GetI18NCategory(I18NCat::MEMSTICK); - // Transfer all the files in /PSP from the original directory. // Should probably be done on a background thread so we can show some UI. // So we probably need another screen for this with a progress bar.. // If the directory itself is called PSP, don't go below. if (moveData_) { - progressReporter_.Set(iz->T("Starting move...")); + progressReporter_.Set(T(I18NCat::MEMSTICK, "Starting move...")); moveDataTask_ = Promise::Spawn(&g_threadManager, [&]() -> MoveResult * { + auto ms = GetI18NCategory(I18NCat::MEMSTICK); Path moveSrc = g_Config.memStickDirectory; Path moveDest = newMemstickFolder_; if (moveSrc.GetFilename() != "PSP") { @@ -666,7 +664,7 @@ UI::EventReturn ConfirmMemstickMoveScreen::OnConfirm(UI::EventParams ¶ms) { // TODO: Handle failure listing files. std::string error = "Failed to read old directory"; INFO_LOG(SYSTEM, "%s", error.c_str()); - progressReporter_.Set(iz->T(error.c_str())); + progressReporter_.Set(ms->T(error.c_str())); return new MoveResult{ false, error }; } @@ -757,12 +755,12 @@ UI::EventReturn ConfirmMemstickMoveScreen::OnConfirm(UI::EventParams ¶ms) { } void ConfirmMemstickMoveScreen::FinishFolderMove() { - auto iz = GetI18NCategory(I18NCat::MEMSTICK); + auto ms = GetI18NCategory(I18NCat::MEMSTICK); // Successful so far, switch the memstick folder. if (!SwitchMemstickFolderTo(newMemstickFolder_)) { // TODO: More precise errors. - error_ = iz->T("That folder doesn't work as a memstick folder."); + error_ = ms->T("That folder doesn't work as a memstick folder."); return; } @@ -779,7 +777,7 @@ void ConfirmMemstickMoveScreen::FinishFolderMove() { // TriggerFinish(DialogResult::DR_OK); screenManager()->switchScreen(new MainScreen()); } else { - error_ = iz->T("Failed to save config"); + error_ = ms->T("Failed to save config"); RecreateViews(); } }