Unicode const char* в JString с использованием JNI и C++
Простой вопрос Как я могу получить jstring из unicode const char*, используя JNI и C++?
Вот моя проблема, и что я уже пробовал:
const char* value = (some value from server);
(*env)->NewStringUTF(value);
Проблема здесь в том, что NewStringUTF возвращает строку UTF, и ему не нравятся некоторые символы, не относящиеся к UTF8 (вроде бы очевидно, но стоит простой попытки).
Попытка 2, используя NewString:
const char* value = (some value from server);
(*env)->NewString(value, strlen(value));
В то время как NewString принимает и возвращает строку в Юникоде, метод strlen(value) не работает, так как для него требуется параметр jsize, а не просто хороший размер или длина.
Как мы получаем JSize? Согласно (очень очень небольшому количеству) документации и онлайн-примерам, вы можете получить jsize из jIntArray. Я не могу найти информацию о том, как преобразовать const char * в какой-нибудь jarray, и в любом случае это может быть плохой идеей.
Другим вариантом будет получить jsize из int в size_t, что мне пока не удалось.
Кто-нибудь сталкивался с этой проблемой, или есть предложения, как ее обойти? Кажется, что jsize - это ключ, который мне не хватает для преобразования в юникод. Кроме того, я использую JNI и Android NDK, на случай, если это кому-нибудь поможет.
Благодарю.
Редактировать Я только что понял, что NewString также ожидает jchar*, поэтому его подпись (jchar*, jsize). Это означает, что даже с jsize const char * не компилируется.
Редактировать 2 Вот исключение, генерируемое во время выполнения при использовании метода NewStringUTF. Это связано с тем, о чем говорит @fadden:
JNI WARNING: NewStringUTF input is not valid Modified UTF-8: illegal start byte 0xb7 03string: ' : Method(d6, us-dev1-api, 0), , 訩�x�m�P)
0 ответов
Как показано в сообщении об ошибке, ваш char* не является допустимым Modifed-utf8, поэтому JVM прерван.
У вас есть два способа их избежать.
- проверьте содержимое char*, чтобы избежать сбоя.
логика проверки в android ART check_jni.cc следующая https://android.googlesource.com/platform/art/+/35e827a/runtime/check_jni.cc
jstring toJString(JNIEnv* env, const char* bytes) {
const char* error = nullptr;
auto utf8 = CheckUtfBytes(bytes, &error);
if (error) {
std::ostringstream msg;
msg << error << " 0x" << std::hex << static_cast<int>(utf8);
throw std::system_error(-1, std::generic_category(), msg.str());
} else {
return env->NewStringUTF(bytes);
}
Таким образом, вы всегда получите действительный jstring
.
- Использование конструктора String для построения из
jbyteArray
.
jstring toJString(JNIEnv *env, const char *pat) {
int len = strlen(pat);
jbyteArray bytes = env->NewByteArray(len);
env->SetByteArrayRegion(bytes, 0, len, (jbyte *) pat);
jstring encoding = env->NewStringUTF("utf-8");
jstring jstr = (jstring) env->NewObject(java_lang_String_class,
java_lang_String_init, bytes, encoding);
env->DeleteLocalRef(encoding);
env->DeleteLocalRef(bytes);
return jstr;
}
Таким образом, вы просто избегаете сбоя, но строка все еще может быть недействительной, и вы дважды копируете память, что плохо работает.