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 прерван.

У вас есть два способа их избежать.

  1. проверьте содержимое 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.

  1. Использование конструктора 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;
}

Таким образом, вы просто избегаете сбоя, но строка все еще может быть недействительной, и вы дважды копируете память, что плохо работает.

Другие вопросы по тегам