Android JNI - Reliable way to convert jstring to wchar_t

匿名 (未验证) 提交于 2019-12-03 09:06:55

问题:

In my Android JNI code, I need to convert jstring to wchar_t. The closest reference I found was How do I convert jstring to wchar_t *.

One can obtain jchar* and the length using the following code:

const jchar *raw = env->GetStringChars(string, 0); jsize len = env->GetStringLength(string);  wchar_t* wStr = new wchar_t[len+1]; 

It seems I cannot use wcncpy to copy "raw" into "wStr." Although jchar is 2-bytes long, wchar_t is 4 bytes long on all modern versions of Android OS.

One option is to copy one character at a time in a for loop:

for(int i=0;i<len;i++) {     wStr[i] = raw[i]; } wStr[len] = 0; 

The other option would be to call env->GetStringUTFChars() and use iconv_* routines to convert to wchar_t type.

Can someone please confirm if option 1 is valid? Hope I don't have to resort to option 2. Is there a better option? Regards.

回答1:

As long as all your data is UCS2, you can use option 1. Please see wchar_t for UTF-16 on Linux? for a similar discussion. Note that C++11 provides std::codecvt_utf16 to deal with the situation.



回答2:

wchar_t specifies an element size but not a character set or encoding. Since you are asking about a 32-bit element, can we assume you want to use Unicode/UTF-32? Regardless, once you decide which encoding you want, standard Java libraries are up to the task.

Use a String.getBytes() overload to get an array of bytes. (It is easier to do this in Java rather than JNI, if you have a choice.) Once you have a jbyteArray, you can copy it to a C buffer and cast to wchar_t *.

On Android, you might want Unicode/UTF-8. But that has an 8-bit code-unit so you probably wouldn't be asking about wchar_t. (BTW-a character in UTF-8 can need 1 or more bytes.)



回答3:

One way would be to use String.getBytes("UTF-32LE"). Note this is making the ASSUMPTION that wchar_t is 4 bytes and little-endian, but this should be a fairly safe assumption to make.

Here's an example that passes a String from Java to C++, where it is converted to std::wstring, reversed, and passed back to Java:

class MyClass {     private native byte[] reverseString(byte[] arr);     String reverseString(String s) {         try {             return new String(reverseString(s.getBytes("UTF-32")), "UTF-32");         } catch (UnsupportedEncodingException e) {             // TODO Auto-generated catch block             e.printStackTrace();             return "";         }     } } 

On the C++ side you have:

std::wstring toWStr(JNIEnv *env, jbyteArray s) {     const wchar_t *buf = (wchar_t*) env->GetByteArrayElements(s, NULL);     int n = env->GetArrayLength(s) / sizeof(wchar_t);      // First byte is BOM (0xfeff), so we skip it, hence the "buf + 1".     // There IS NO null-terminator.     std::wstring ret(buf + 1, buf + n);      env->ReleaseByteArrayElements(s, (jbyte*) buf, 0);     return ret; }  jbyteArray fromWStr(JNIEnv *env, const std::wstring &s) {     jbyteArray ret = env->NewByteArray((s.size()+1)*sizeof(wchar_t));      // Add the BOM in front.     wchar_t bom = 0xfeff;     env->SetByteArrayRegion(ret, 0, sizeof(wchar_t), (const jbyte*) &bom);      env->SetByteArrayRegion(ret, sizeof(wchar_t), s.size()*sizeof(wchar_t), (const jbyte*) s.c_str());     return ret; }  extern "C" JNIEXPORT jbyteArray JNICALL Java_MyClass_reverseString(JNIEnv *env, jobject thiz, jbyteArray arr) {     std::wstring s= toWStr(env, arr);     std::reverse(s.begin(), s.end());     return fromWStr(env, s); } 

I tested it both on my phone, which has Android 4.1.2 and ARM CPU, and on the Android Emulator - Android 4.4.2 and x86 CPU, and this code:

MyClass obj = new MyClass(); Log.d("test", obj.reverseString("hello, здравствуйте, 您好, こんにちは")); 

Gave this output:

06-04 17:18:20.605: D/test(8285): はちにんこ ,好您 ,етйувтсвардз ,olleh 


回答4:

No need to convert. Cast const jchar to (wchar_t *). jni.h define jchar as typedef uint16_t jchar; /* unsigned 16 bits */ which is eventually wchar_t.

You can try this, it worked for me in old project.



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