From 05b860c1677f086d0c8e758956f9a97783d7509b Mon Sep 17 00:00:00 2001 From: The Dax Date: Tue, 27 Aug 2013 07:20:41 -0400 Subject: [PATCH 1/6] Win32: Update OSK bypass with Unicode/wchar/wstring support. --- Core/Dialog/PSPOskDialog.cpp | 71 +++++++++++++++++++++++------------- Core/Host.h | 1 + Windows/InputBox.cpp | 22 +++++++++++ Windows/InputBox.h | 1 + Windows/WindowsHost.cpp | 9 +++++ Windows/WindowsHost.h | 2 +- 6 files changed, 79 insertions(+), 27 deletions(-) diff --git a/Core/Dialog/PSPOskDialog.cpp b/Core/Dialog/PSPOskDialog.cpp index bf75a483bb..9eb4c63524 100755 --- a/Core/Dialog/PSPOskDialog.cpp +++ b/Core/Dialog/PSPOskDialog.cpp @@ -160,6 +160,27 @@ void PSPOskDialog::ConvertUCS2ToUTF8(std::string& _string, const PSPPointer em_address) +{ + if (!em_address.IsValid()) + { + _string = L""; + return; + } + + wchar_t stringBuffer[2048]; + wchar_t *string = stringBuffer; + + auto input = em_address; + int c; + while ((c = *input++) != 0) + { + *string++ = c; + } + *string++ = '\0'; + _string = stringBuffer; +} + void PSPOskDialog::ConvertUCS2ToUTF8(std::string& _string, const wchar_t *input) { char stringBuffer[2048]; @@ -742,7 +763,7 @@ void PSPOskDialog::RenderKeyboard() // TODO: Use a wstring to allow Japanese/Russian/etc.. on _WIN32(others?) int PSPOskDialog::NativeKeyboard() { - char *input = new char[FieldMaxLength()]; + wchar_t *input = new wchar_t[FieldMaxLength()]; memset(input, 0, sizeof(input)); if (status == SCE_UTILITY_STATUS_INITIALIZE) @@ -752,37 +773,35 @@ int PSPOskDialog::NativeKeyboard() else if (status == SCE_UTILITY_STATUS_RUNNING) { - - std::string initial_text; - ConvertUCS2ToUTF8(initial_text, oskParams->fields[0].intext); + std::wstring titleText; + GetWideStringFromPSPPointer(titleText, oskParams->fields[0].desc); - const size_t defaultText_len = 512; - char defaultText[defaultText_len]; + std::wstring defaultText; + GetWideStringFromPSPPointer(defaultText, oskParams->fields[0].intext); - memset(defaultText, 0, sizeof(defaultText)); + if(defaultText.length() <= 0) + defaultText.assign(L"VALUE"); - if(initial_text.length() < defaultText_len) - strncat(defaultText, initial_text.c_str(), strlen(initial_text.c_str())); - else { - ERROR_LOG(HLE, "NativeKeyboard: initial text length is too long"); - strncat(defaultText, "VALUE", strlen("VALUE")); + std::wstring inputWide; + + if(!host->InputBoxGetWString(titleText.c_str(), defaultText, inputWide)) + { + wcsncat(input, L"", wcslen(L"")); } + else + { + size_t maxInputLength = FieldMaxLength(); - char windowTitle[defaultText_len]; - memset(windowTitle, 0, sizeof(windowTitle)); - - std::string description_text; - ConvertUCS2ToUTF8(description_text, oskParams->fields[0].desc); - - if(description_text.length() < defaultText_len) - strncat(windowTitle, description_text.c_str(), strlen(description_text.c_str())); - - size_t maxInputLength = FieldMaxLength(); - - if(host->InputBoxGetString(windowTitle, defaultText, input, maxInputLength)) { - strncat(input, "", strlen("")); + if(inputWide.length() < maxInputLength) + { + wcsncat(input, inputWide.c_str(), inputWide.length()); + } + else + { + ERROR_LOG(HLE, "NativeKeyboard: input text too long. Try again."); + wcsncat(input, L"", wcslen(L"")); + } } - status = SCE_UTILITY_STATUS_FINISHED; } else if (status == SCE_UTILITY_STATUS_FINISHED) diff --git a/Core/Host.h b/Core/Host.h index 457bd782c2..f13f378a5a 100644 --- a/Core/Host.h +++ b/Core/Host.h @@ -68,6 +68,7 @@ public: #ifdef _WIN32 // Implement this on your platform to grab text input from the user for whatever purpose. virtual bool InputBoxGetString(char *title, const char *defaultValue, char *outValue, size_t outlength) { return false; } + virtual bool InputBoxGetWString(const wchar_t *title, const std::wstring &defaultvalue, std::wstring &outvalue) { return false; } #endif // Used for headless. diff --git a/Windows/InputBox.cpp b/Windows/InputBox.cpp index 9f7d0b9459..7d24b4f2b4 100644 --- a/Windows/InputBox.cpp +++ b/Windows/InputBox.cpp @@ -85,6 +85,28 @@ bool InputBox_GetString(HINSTANCE hInst, HWND hParent, const wchar_t *title, con return false; } +bool InputBox_GetWString(HINSTANCE hInst, HWND hParent, const wchar_t *title, const std::wstring &defaultValue, std::wstring &outvalue) +{ + const wchar_t *defaultTitle = L"Input value"; + defaultSelected = true; + + textBoxContents = defaultValue; + + if (title && wcslen(title) <= 0) + windowTitle = defaultTitle; + else if (title && wcslen(title) < 255) + windowTitle = title; + else + windowTitle = defaultTitle; + + if (IDOK == DialogBox(hInst, (LPCWSTR)IDD_INPUTBOX, hParent, InputBoxFunc)) { + outvalue = out; + return true; + } + else + return false; +} + bool InputBox_GetHex(HINSTANCE hInst, HWND hParent, const wchar_t *title, u32 defaultvalue, u32 &outvalue) { wchar_t temp[256]; diff --git a/Windows/InputBox.h b/Windows/InputBox.h index 673ffe3c65..fdfc1ebd6b 100644 --- a/Windows/InputBox.h +++ b/Windows/InputBox.h @@ -8,4 +8,5 @@ // All I/O is in UTF-8 bool InputBox_GetString(HINSTANCE hInst, HWND hParent, const wchar_t *title, const std::string &defaultvalue, std::string &outvalue, bool selected); bool InputBox_GetString(HINSTANCE hInst, HWND hParent, const wchar_t *title, const std::string &defaultvalue, std::string &outvalue); +bool InputBox_GetWString(HINSTANCE hInst, HWND hParent, const wchar_t *title, const std::wstring &defaultvalue, std::wstring &outvalue); bool InputBox_GetHex(HINSTANCE hInst, HWND hParent, const wchar_t *title, u32 defaultvalue, u32 &outvalue); diff --git a/Windows/WindowsHost.cpp b/Windows/WindowsHost.cpp index 1baac21b85..76acb3a272 100644 --- a/Windows/WindowsHost.cpp +++ b/Windows/WindowsHost.cpp @@ -309,6 +309,15 @@ bool WindowsHost::InputBoxGetString(char *title, const char *defaultValue, char } } +bool WindowsHost::InputBoxGetWString(const wchar_t *title, const std::wstring &defaultvalue, std::wstring &outvalue) +{ + if (InputBox_GetWString(MainWindow::GetHInstance(), MainWindow::GetHWND(), title, defaultvalue, outvalue)) { + return true; + } else { + return false; + } +} + // http://msdn.microsoft.com/en-us/library/aa969393.aspx HRESULT CreateLink(LPCWSTR lpszPathObj, LPCWSTR lpszArguments, LPCWSTR lpszPathLink, LPCWSTR lpszDesc) { diff --git a/Windows/WindowsHost.h b/Windows/WindowsHost.h index 20b3e91dff..2c4d5c463a 100644 --- a/Windows/WindowsHost.h +++ b/Windows/WindowsHost.h @@ -59,7 +59,7 @@ public: virtual bool CreateDesktopShortcut(std::string argumentPath, std::string title); bool InputBoxGetString(char *title, const char *defaultValue, char *outValue, size_t outlength); - + bool InputBoxGetWString(const wchar_t *title, const std::wstring &defaultvalue, std::wstring &outvalue); std::shared_ptr keyboard; private: From 58ca962d89b29cb66c91dd97a6e6fe9aa90084c2 Mon Sep 17 00:00:00 2001 From: The Dax Date: Tue, 27 Aug 2013 07:44:32 -0400 Subject: [PATCH 2/6] Prevent possible buffer overflow. --- Core/Dialog/PSPOskDialog.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Core/Dialog/PSPOskDialog.cpp b/Core/Dialog/PSPOskDialog.cpp index 9eb4c63524..112909658d 100755 --- a/Core/Dialog/PSPOskDialog.cpp +++ b/Core/Dialog/PSPOskDialog.cpp @@ -162,13 +162,14 @@ void PSPOskDialog::ConvertUCS2ToUTF8(std::string& _string, const PSPPointer em_address) { - if (!em_address.IsValid()) + const size_t maxLength = 2048; + if (!em_address.IsValid() || _string.length() >= maxLength) { _string = L""; return; } - wchar_t stringBuffer[2048]; + wchar_t stringBuffer[maxLength]; wchar_t *string = stringBuffer; auto input = em_address; From 2e25f005851d4736f13e3a7d35321d5c7ee8d5b4 Mon Sep 17 00:00:00 2001 From: The Dax Date: Tue, 27 Aug 2013 08:02:42 -0400 Subject: [PATCH 3/6] Really prevent the possible buffer overflow. This is getting silly. --- Core/Dialog/PSPOskDialog.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Core/Dialog/PSPOskDialog.cpp b/Core/Dialog/PSPOskDialog.cpp index 112909658d..958f3d2cb7 100755 --- a/Core/Dialog/PSPOskDialog.cpp +++ b/Core/Dialog/PSPOskDialog.cpp @@ -162,21 +162,23 @@ void PSPOskDialog::ConvertUCS2ToUTF8(std::string& _string, const PSPPointer em_address) { - const size_t maxLength = 2048; - if (!em_address.IsValid() || _string.length() >= maxLength) + if (!em_address.IsValid()) { _string = L""; return; } + const size_t maxLength = 2048; wchar_t stringBuffer[maxLength]; wchar_t *string = stringBuffer; auto input = em_address; int c; + u32_le count; while ((c = *input++) != 0) { - *string++ = c; + if ( !(++count >= maxLength) ) + *string++ = c; } *string++ = '\0'; _string = stringBuffer; From f70faaa0c267ab5ed7fae8eb2c3e72c39eed2f81 Mon Sep 17 00:00:00 2001 From: The Dax Date: Tue, 27 Aug 2013 08:08:06 -0400 Subject: [PATCH 4/6] Terminate the loop early if it's going to overflow; there's no reason to keep riding it out. Also fix use of uninitialized variable. --- Core/Dialog/PSPOskDialog.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Core/Dialog/PSPOskDialog.cpp b/Core/Dialog/PSPOskDialog.cpp index 958f3d2cb7..b87b60bb7d 100755 --- a/Core/Dialog/PSPOskDialog.cpp +++ b/Core/Dialog/PSPOskDialog.cpp @@ -174,11 +174,13 @@ void GetWideStringFromPSPPointer(std::wstring& _string, const PSPPointer auto input = em_address; int c; - u32_le count; + u32_le count = 0; while ((c = *input++) != 0) { if ( !(++count >= maxLength) ) *string++ = c; + else + break; } *string++ = '\0'; _string = stringBuffer; From 3c303925c90567e35a9798ee1e39a5338aa39327 Mon Sep 17 00:00:00 2001 From: The Dax Date: Tue, 27 Aug 2013 08:41:59 -0400 Subject: [PATCH 5/6] Change u32_le to u32. --- Core/Dialog/PSPOskDialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/Dialog/PSPOskDialog.cpp b/Core/Dialog/PSPOskDialog.cpp index b87b60bb7d..f0d9fee9b5 100755 --- a/Core/Dialog/PSPOskDialog.cpp +++ b/Core/Dialog/PSPOskDialog.cpp @@ -174,7 +174,7 @@ void GetWideStringFromPSPPointer(std::wstring& _string, const PSPPointer auto input = em_address; int c; - u32_le count = 0; + u32 count = 0; while ((c = *input++) != 0) { if ( !(++count >= maxLength) ) From d5c4f6673cb9b09f221ba4de069c86571600b5b3 Mon Sep 17 00:00:00 2001 From: The Dax Date: Tue, 27 Aug 2013 08:46:54 -0400 Subject: [PATCH 6/6] Switch from u32_le to u32, and truncate the user's input if it's too long(so that they still get something entered. It's probably confusing not to enter something). --- Core/Dialog/PSPOskDialog.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/Dialog/PSPOskDialog.cpp b/Core/Dialog/PSPOskDialog.cpp index f0d9fee9b5..e0864e1c86 100755 --- a/Core/Dialog/PSPOskDialog.cpp +++ b/Core/Dialog/PSPOskDialog.cpp @@ -803,8 +803,8 @@ int PSPOskDialog::NativeKeyboard() } else { - ERROR_LOG(HLE, "NativeKeyboard: input text too long. Try again."); - wcsncat(input, L"", wcslen(L"")); + ERROR_LOG(HLE, "NativeKeyboard: input text too long(%d characters/glyphs max), truncating to game-requested length.", maxInputLength); + wcsncat(input, inputWide.c_str(), maxInputLength); } } status = SCE_UTILITY_STATUS_FINISHED;