Unicode const char* to JString using JNI and C++

跟風遠走 提交于 2020-03-22 07:31:28

问题


Simple question. How can I get a jstring out of a unicode const char*, using JNI and C++?

Here's my issue, and what I have already tried:

const char* value = (some value from server);
(*env)->NewStringUTF(value);

The issue here is that NewStringUTF returns a UTF string, and it does not like some of the non-UTF8 characters (kind of obvious, but worth a simple try).

Attempt 2, using NewString:

const char* value = (some value from server);
(*env)->NewString(value, strlen(value));

While NewString accepts and returns a unicode string, the strlen(value) method does not work because it requires a jsize param instead of just a good ol' size_t or length.

How do we get a jsize? According to the (very very small amount of) documentation and online examples, you can get the jsize out of a jIntArray. I can't find information on how to convert a const char* to jarray of some sort, and this might be a bad idea anyways.

The other option would be to get the jsize out of the int in size_t, which I haven't succeed at yet either.

Has anyone come across this issue, or has suggestions on how to get around it? It seems like jsize is the key I'm missing for the unicode conversion. Also, I'm using JNI and the Android NDK, in case it helps anyone.

Thanks.

Edit I just realized NewString is also expecting a jchar*, so its signature is (jchar*, jsize). This means that even with the jsize the const char* does not compile.

Edit 2 Here's the exception being thrown at runtime when using the NewStringUTF method. This is related to what @fadden is talking about:

JNI WARNING: NewStringUTF input is not valid Modified UTF-8: illegal start byte 0xb7 03string: ' : Method(d6, us-dev1-api, 0), , 訩�x�m�P)

回答1:


As the error message shows, your char* is not a valid Modifed-utf8, so the JVM aborted.

You got two methods to avoid them.

  1. check char* content to avoid a crash.

the check logic in android ART check_jni.cc is as following https://android.googlesource.com/platform/art/+/35e827a/runtime/check_jni.cc#1273

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);
    }

This way, you always get a valid jstring.

  1. Using String constructor to build from a 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;
}

This way, you just avoid the crash, but the string may be still not valid, and you copy memory twice, which performs badly.



来源:https://stackoverflow.com/questions/28990038/unicode-const-char-to-jstring-using-jni-and-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!