diff --git a/src/android/app/src/main/jni/CMakeLists.txt b/src/android/app/src/main/jni/CMakeLists.txt index 77b95130d..443b39d57 100644 --- a/src/android/app/src/main/jni/CMakeLists.txt +++ b/src/android/app/src/main/jni/CMakeLists.txt @@ -1,4 +1,6 @@ add_library(citra-android SHARED + android_common/android_common.cpp + android_common/android_common.h applets/mii_selector.cpp applets/mii_selector.h applets/swkbd.cpp diff --git a/src/android/app/src/main/jni/android_common/android_common.cpp b/src/android/app/src/main/jni/android_common/android_common.cpp new file mode 100644 index 000000000..dedd33151 --- /dev/null +++ b/src/android/app/src/main/jni/android_common/android_common.cpp @@ -0,0 +1,32 @@ +// Copyright 2022 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "jni/android_common/android_common.h" + +#include +#include + +#include + +#include "common/string_util.h" + +std::string GetJString(JNIEnv* env, jstring jstr) { + if (!jstr) { + return {}; + } + + const jchar* jchars = env->GetStringChars(jstr, nullptr); + const jsize length = env->GetStringLength(jstr); + const std::u16string_view string_view(reinterpret_cast(jchars), length); + const std::string converted_string = Common::UTF16ToUTF8(string_view); + env->ReleaseStringChars(jstr, jchars); + + return converted_string; +} + +jstring ToJString(JNIEnv* env, std::string_view str) { + const std::u16string converted_string = Common::UTF8ToUTF16(str); + return env->NewString(reinterpret_cast(converted_string.data()), + static_cast(converted_string.size())); +} diff --git a/src/android/app/src/main/jni/android_common/android_common.h b/src/android/app/src/main/jni/android_common/android_common.h new file mode 100644 index 000000000..a09f7bc45 --- /dev/null +++ b/src/android/app/src/main/jni/android_common/android_common.h @@ -0,0 +1,12 @@ +// Copyright 2022 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include + +#include + +std::string GetJString(JNIEnv* env, jstring jstr); +jstring ToJString(JNIEnv* env, std::string_view str); diff --git a/src/android/app/src/main/jni/applets/mii_selector.cpp b/src/android/app/src/main/jni/applets/mii_selector.cpp index 0e8e79238..2009a84ec 100644 --- a/src/android/app/src/main/jni/applets/mii_selector.cpp +++ b/src/android/app/src/main/jni/applets/mii_selector.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include "common/string_util.h" +#include "jni/android_common/android_common.h" #include "jni/applets/mii_selector.h" #include "jni/id_cache.h" @@ -26,7 +27,7 @@ void AndroidMiiSelector::Setup(const Frontend::MiiSelectorConfig& config) { static_cast(config.enable_cancel_button)); env->SetObjectField(java_config, env->GetFieldID(s_mii_selector_config_class, "title", "Ljava/lang/String;"), - env->NewStringUTF(config.title.c_str())); + ToJString(env, config.title)); env->SetLongField( java_config, env->GetFieldID(s_mii_selector_config_class, "initially_selected_mii_index", "J"), @@ -39,7 +40,7 @@ void AndroidMiiSelector::Setup(const Frontend::MiiSelectorConfig& config) { env->NewObjectArray(static_cast(miis.size()), string_class, nullptr); for (std::size_t i = 0; i < miis.size(); ++i) { const auto name = Common::UTF16BufferToUTF8(miis[i].mii_name); - env->SetObjectArrayElement(array, static_cast(i), env->NewStringUTF(name.c_str())); + env->SetObjectArrayElement(array, static_cast(i), ToJString(env, name)); } env->SetObjectField( java_config, diff --git a/src/android/app/src/main/jni/applets/swkbd.cpp b/src/android/app/src/main/jni/applets/swkbd.cpp index 062d307a6..e373c9e27 100644 --- a/src/android/app/src/main/jni/applets/swkbd.cpp +++ b/src/android/app/src/main/jni/applets/swkbd.cpp @@ -3,22 +3,14 @@ // Refer to the license.txt file included. #include + #include + #include "core/core.h" +#include "jni/android_common/android_common.h" #include "jni/applets/swkbd.h" #include "jni/id_cache.h" -static std::string GetJString(JNIEnv* env, jstring jstr) { - if (!jstr) { - return {}; - } - - const char* s = env->GetStringUTFChars(jstr, nullptr); - std::string result = s; - env->ReleaseStringUTFChars(jstr, s); - return result; -} - static jclass s_software_keyboard_class; static jclass s_keyboard_config_class; static jclass s_keyboard_data_class; @@ -39,15 +31,15 @@ static jobject ToJavaKeyboardConfig(const Frontend::KeyboardConfig& config) { static_cast(config.multiline_mode)); env->SetObjectField(object, env->GetFieldID(s_keyboard_config_class, "hint_text", "Ljava/lang/String;"), - env->NewStringUTF(config.hint_text.c_str())); + ToJString(env, config.hint_text)); const jclass string_class = reinterpret_cast(env->FindClass("java/lang/String")); const jobjectArray array = env->NewObjectArray(static_cast(config.button_text.size()), string_class, - env->NewStringUTF(config.button_text[0].c_str())); + ToJString(env, config.button_text[0])); for (std::size_t i = 1; i < config.button_text.size(); ++i) { env->SetObjectArrayElement(array, static_cast(i), - env->NewStringUTF(config.button_text[i].c_str())); + ToJString(env, config.button_text[i])); } env->SetObjectField( object, env->GetFieldID(s_keyboard_config_class, "button_text", "[Ljava/lang/String;"), @@ -78,8 +70,7 @@ void AndroidKeyboard::Execute(const Frontend::KeyboardConfig& config) { void AndroidKeyboard::ShowError(const std::string& error) { JNIEnv* env = IDCache::GetEnvForThread(); - env->CallStaticVoidMethod(s_software_keyboard_class, s_swkbd_show_error, - env->NewStringUTF(error.c_str())); + env->CallStaticVoidMethod(s_software_keyboard_class, s_swkbd_show_error, ToJString(env, error)); } void InitJNI(JNIEnv* env) { diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index 6dffc1225..e876ecb3e 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp @@ -27,6 +27,7 @@ #include "core/hle/service/nfc/nfc.h" #include "core/savestate.h" #include "core/settings.h" +#include "jni/android_common/android_common.h" #include "jni/applets/mii_selector.h" #include "jni/applets/swkbd.h" #include "jni/camera/ndk_camera.h" @@ -58,24 +59,13 @@ std::condition_variable running_cv; } // Anonymous namespace -static std::string GetJString(JNIEnv* env, jstring jstr) { - if (!jstr) { - return {}; - } - - const char* s = env->GetStringUTFChars(jstr, nullptr); - std::string result = s; - env->ReleaseStringUTFChars(jstr, s); - return result; -} - static bool DisplayAlertMessage(const char* caption, const char* text, bool yes_no) { JNIEnv* env = IDCache::GetEnvForThread(); // Execute the Java method. jboolean result = env->CallStaticBooleanMethod( - IDCache::GetNativeLibraryClass(), IDCache::GetDisplayAlertMsg(), env->NewStringUTF(caption), - env->NewStringUTF(text), yes_no ? JNI_TRUE : JNI_FALSE); + IDCache::GetNativeLibraryClass(), IDCache::GetDisplayAlertMsg(), ToJString(env, caption), + ToJString(env, text), yes_no ? JNI_TRUE : JNI_FALSE); return result != JNI_FALSE; } @@ -84,8 +74,8 @@ static std::string DisplayAlertPrompt(const char* caption, const char* text, int JNIEnv* env = IDCache::GetEnvForThread(); jstring value = reinterpret_cast(env->CallStaticObjectMethod( - IDCache::GetNativeLibraryClass(), IDCache::GetDisplayAlertPrompt(), - env->NewStringUTF(caption), env->NewStringUTF(text), buttonConfig)); + IDCache::GetNativeLibraryClass(), IDCache::GetDisplayAlertPrompt(), ToJString(env, caption), + ToJString(env, text), buttonConfig)); return GetJString(env, value); } diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp index 395cf1d38..47aaddddb 100644 --- a/src/common/string_util.cpp +++ b/src/common/string_util.cpp @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include "common/common_paths.h" #include "common/logging/log.h" #include "common/string_util.h" @@ -135,14 +137,14 @@ std::string ReplaceAll(std::string result, const std::string& src, const std::st return result; } -std::string UTF16ToUTF8(const std::u16string& input) { +std::string UTF16ToUTF8(std::u16string_view input) { std::wstring_convert, char16_t> convert; - return convert.to_bytes(input); + return convert.to_bytes(input.data(), input.data() + input.size()); } -std::u16string UTF8ToUTF16(const std::string& input) { +std::u16string UTF8ToUTF16(std::string_view input) { std::wstring_convert, char16_t> convert; - return convert.from_bytes(input); + return convert.from_bytes(input.data(), input.data() + input.size()); } #ifdef _WIN32 diff --git a/src/common/string_util.h b/src/common/string_util.h index 2c454bb7b..d9edbf803 100644 --- a/src/common/string_util.h +++ b/src/common/string_util.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "common/common_types.h" #include "common/swap.h" @@ -37,8 +38,8 @@ void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _P [[nodiscard]] std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest); -[[nodiscard]] std::string UTF16ToUTF8(const std::u16string& input); -[[nodiscard]] std::u16string UTF8ToUTF16(const std::string& input); +[[nodiscard]] std::string UTF16ToUTF8(std::u16string_view input); +[[nodiscard]] std::u16string UTF8ToUTF16(std::string_view input); #ifdef _WIN32 [[nodiscard]] std::string UTF16ToUTF8(const std::wstring& input);