Compare commits

...

3 Commits

5 changed files with 137 additions and 9 deletions

View File

@ -68,4 +68,8 @@ target_link_libraries(${CMAKE_PROJECT_NAME}
log
fmt)
if (ANDROID AND ANDROID_PLATFORM_LEVEL GREATER_EQUAL 31)
target_link_libraries(${CMAKE_PROJECT_NAME} icu)
endif()
target_compile_features(${CMAKE_PROJECT_NAME} PRIVATE cxx_std_23)

View File

@ -1,11 +1,12 @@
#include "Misc.hpp"
#include <codecvt>
#include <locale>
#include "fmt/core.h"
#ifndef GKMS_WINDOWS
#include <jni.h>
#if defined(__ANDROID__) && __ANDROID_API__ >= 31
#include <unicode/ustring.h>
#endif
extern JavaVM* g_javaVM;
#else
@ -32,14 +33,136 @@ namespace GakumasLocal::Misc {
return utility::conversions::utf16_to_utf8(wstr);
}
#else
namespace {
jclass GetStringClass(JNIEnv* env) {
static jclass stringClass = nullptr;
if (stringClass) return stringClass;
jclass localClass = env->FindClass("java/lang/String");
if (!localClass) return nullptr;
stringClass = reinterpret_cast<jclass>(env->NewGlobalRef(localClass));
env->DeleteLocalRef(localClass);
return stringClass;
}
jstring GetUtf8CharsetName(JNIEnv* env) {
static jstring utf8Charset = nullptr;
if (utf8Charset) return utf8Charset;
jstring localUtf8 = env->NewStringUTF("UTF-8");
if (!localUtf8) return nullptr;
utf8Charset = reinterpret_cast<jstring>(env->NewGlobalRef(localUtf8));
env->DeleteLocalRef(localUtf8);
return utf8Charset;
}
}
std::u16string ToUTF16(const std::string_view& str) {
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> utf16conv;
return utf16conv.from_bytes(str.data(), str.data() + str.size());
#if defined(__ANDROID__) && __ANDROID_API__ >= 31
UErrorCode status = U_ZERO_ERROR;
int32_t outLen = 0;
u_strFromUTF8(nullptr, 0, &outLen, str.data(), static_cast<int32_t>(str.size()), &status);
if (status != U_BUFFER_OVERFLOW_ERROR && U_FAILURE(status)) return {};
status = U_ZERO_ERROR;
std::u16string out(outLen, u'\0');
u_strFromUTF8(
reinterpret_cast<UChar*>(out.data()),
outLen,
&outLen,
str.data(),
static_cast<int32_t>(str.size()),
&status);
if (U_FAILURE(status)) return {};
out.resize(outLen);
return out;
#else
JNIEnv* env = GetJNIEnv();
if (!env) return {};
jclass stringClass = GetStringClass(env);
jstring utf8Charset = GetUtf8CharsetName(env);
if (!stringClass || !utf8Charset) return {};
jmethodID ctor = env->GetMethodID(stringClass, "<init>", "([BLjava/lang/String;)V");
if (!ctor) return {};
jbyteArray bytes = env->NewByteArray(static_cast<jsize>(str.size()));
if (!bytes) return {};
env->SetByteArrayRegion(bytes, 0, static_cast<jsize>(str.size()), reinterpret_cast<const jbyte*>(str.data()));
jstring jstr = reinterpret_cast<jstring>(env->NewObject(stringClass, ctor, bytes, utf8Charset));
env->DeleteLocalRef(bytes);
if (!jstr || env->ExceptionCheck()) {
env->ExceptionClear();
if (jstr) env->DeleteLocalRef(jstr);
return {};
}
const jsize len = env->GetStringLength(jstr);
const jchar* chars = env->GetStringChars(jstr, nullptr);
if (!chars) {
env->DeleteLocalRef(jstr);
return {};
}
std::u16string out(reinterpret_cast<const char16_t*>(chars), reinterpret_cast<const char16_t*>(chars) + len);
env->ReleaseStringChars(jstr, chars);
env->DeleteLocalRef(jstr);
return out;
#endif
}
std::string ToUTF8(const std::u16string_view& str) {
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> utf16conv;
return utf16conv.to_bytes(str.data(), str.data() + str.size());
#if defined(__ANDROID__) && __ANDROID_API__ >= 31
UErrorCode status = U_ZERO_ERROR;
int32_t outLen = 0;
u_strToUTF8(nullptr, 0, &outLen, reinterpret_cast<const UChar*>(str.data()), static_cast<int32_t>(str.size()), &status);
if (status != U_BUFFER_OVERFLOW_ERROR && U_FAILURE(status)) return {};
status = U_ZERO_ERROR;
std::string out(outLen, '\0');
u_strToUTF8(
out.data(),
outLen,
&outLen,
reinterpret_cast<const UChar*>(str.data()),
static_cast<int32_t>(str.size()),
&status);
if (U_FAILURE(status)) return {};
out.resize(outLen);
return out;
#else
JNIEnv* env = GetJNIEnv();
if (!env) return {};
jclass stringClass = GetStringClass(env);
jstring utf8Charset = GetUtf8CharsetName(env);
if (!stringClass || !utf8Charset) return {};
jstring jstr = env->NewString(reinterpret_cast<const jchar*>(str.data()), static_cast<jsize>(str.size()));
if (!jstr) return {};
jmethodID getBytes = env->GetMethodID(stringClass, "getBytes", "(Ljava/lang/String;)[B");
if (!getBytes) {
env->DeleteLocalRef(jstr);
return {};
}
jbyteArray bytes = reinterpret_cast<jbyteArray>(env->CallObjectMethod(jstr, getBytes, utf8Charset));
env->DeleteLocalRef(jstr);
if (!bytes || env->ExceptionCheck()) {
env->ExceptionClear();
if (bytes) env->DeleteLocalRef(bytes);
return {};
}
const jsize len = env->GetArrayLength(bytes);
std::string out(static_cast<size_t>(len), '\0');
env->GetByteArrayRegion(bytes, 0, len, reinterpret_cast<jbyte*>(out.data()));
env->DeleteLocalRef(bytes);
return out;
#endif
}
#endif

View File

@ -565,10 +565,10 @@ public:
}
catch (...) {
std::cout << funcName << " Invoke Error\n";
Return();
return Return();
}
}
Return();
return Return();
}
inline static std::vector<Assembly*> assembly;

View File

@ -1,3 +1,3 @@
minApiVersion=101
targetApiVersion=101
staticScope=false
staticScope=true

View File

@ -0,0 +1 @@
com.bandainamcoent.idolmaster_gakuen