使用 JNI 将 4 字节 wchar_t 转换为字符串
4-byte wchar_t to String conversion using JNI
所以我有这个 CanvasView,它显示我的应用程序的调试信息。它基本上是透明背景的叠加视图,因此 canvas 中绘制的所有内容都在屏幕中浮动。由于我需要来自 returns wchar_t* 的本机 c++ 的一些信息,我如何使用 env->NewString
因为 android 现在使 wchar_t 是 4 个字节,而 jchar 是2 个字节?
我的 java 在我的库中调用本机 c++ 函数的代码:
private static String get_Name();
private class CanvasView extends View{
public CanvasView(Context context){
super(context);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paintText = new Paint();
paintText.setStyle(Paint.Style.FILL);
paintText.setColor(Color.WHITE);
paintText.setShadowLayer(5.5f, 0, 0, Color.BLACK);
paintText.setTextSize(convertSizeToDp(7.5f));
paintText.setTextAlign(Paint.Align.LEFT);
paintText.drawText(get_Name(), x, y, paintText);
// the rest of the code
// ...
}
}
get_Name
基本上 return 来自 NewString((const jchar* )myWchar, myLen)
的 jstring
return 结果有时是非 unicode 字符串,甚至我的应用程序在调用 NewString
时崩溃。
wchar_t
是 2 个字节的唯一平台是 Windows。在其他平台上,wchar_t
是 4 个字节。 env->NewString()
将 UTF-16 数据作为输入,因此您必须在调用 env->NewString()
之前将 wchar_t
数据从 UTF-32 转换为 UTF-16。否则,您将不得不使用 JNI 调用 Java String
构造函数,该构造函数采用 byte[]
数组和字符集作为输入,因此您可以直接从 UTF-32 数据创建字符串。
首先,使用JNI分配一个ByteBuffer
:
wchar_t *input = ...;
jobject bb = env->NewDirectByteBuffer((void *) input, wcslen(input) * sizeof(wchar_t));
接下来,调用Charset.forName("UTF-32LE").decode(bb).toString()
:(每段为一步)
jclass cls_Charset = env->FindClass("java/nio/charset/Charset");
jmethodID mid_Charset_forName = env->GetStaticMethodID(cls_Charset, "forName", "(Ljava/lang/String;)Ljava/nio/charset/Charset;");
jobject charset = env->CallStaticObjectMethod(cls_Charset, mid_Charset_forName, env->NewStringUTF("UTF-32LE"));
jmethodID mid_Charset_decode = env->GetMethodID(cls_Charset, "decode", "(Ljava/nio/ByteBuffer;)Ljava/nio/CharBuffer;");
jobject cb = env->CallObjectMethod(charset, mid_Charset_decode, bb);
jclass cls_CharBuffer = env->FindClass("java/nio/CharBuffer");
jmethodID mid_CharBuffer_toString = env->GetMethodID(cls_CharBuffer, "toString", "()Ljava/lang/String;");
jstring ret = env->CallObjectMethod(cb, mid_CharBuffer_toString);
return ret;
注意:这取决于您所在平台的字节顺序。从 this answer 看来所有 Android 平台都是小端。如果您使用的是大端平台,则可能需要使用 UTF-32BE
。
所以我有这个 CanvasView,它显示我的应用程序的调试信息。它基本上是透明背景的叠加视图,因此 canvas 中绘制的所有内容都在屏幕中浮动。由于我需要来自 returns wchar_t* 的本机 c++ 的一些信息,我如何使用 env->NewString
因为 android 现在使 wchar_t 是 4 个字节,而 jchar 是2 个字节?
我的 java 在我的库中调用本机 c++ 函数的代码:
private static String get_Name();
private class CanvasView extends View{
public CanvasView(Context context){
super(context);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paintText = new Paint();
paintText.setStyle(Paint.Style.FILL);
paintText.setColor(Color.WHITE);
paintText.setShadowLayer(5.5f, 0, 0, Color.BLACK);
paintText.setTextSize(convertSizeToDp(7.5f));
paintText.setTextAlign(Paint.Align.LEFT);
paintText.drawText(get_Name(), x, y, paintText);
// the rest of the code
// ...
}
}
get_Name
基本上 return 来自 NewString((const jchar* )myWchar, myLen)
return 结果有时是非 unicode 字符串,甚至我的应用程序在调用 NewString
时崩溃。
wchar_t
是 2 个字节的唯一平台是 Windows。在其他平台上,wchar_t
是 4 个字节。 env->NewString()
将 UTF-16 数据作为输入,因此您必须在调用 env->NewString()
之前将 wchar_t
数据从 UTF-32 转换为 UTF-16。否则,您将不得不使用 JNI 调用 Java String
构造函数,该构造函数采用 byte[]
数组和字符集作为输入,因此您可以直接从 UTF-32 数据创建字符串。
首先,使用JNI分配一个ByteBuffer
:
wchar_t *input = ...;
jobject bb = env->NewDirectByteBuffer((void *) input, wcslen(input) * sizeof(wchar_t));
接下来,调用Charset.forName("UTF-32LE").decode(bb).toString()
:(每段为一步)
jclass cls_Charset = env->FindClass("java/nio/charset/Charset");
jmethodID mid_Charset_forName = env->GetStaticMethodID(cls_Charset, "forName", "(Ljava/lang/String;)Ljava/nio/charset/Charset;");
jobject charset = env->CallStaticObjectMethod(cls_Charset, mid_Charset_forName, env->NewStringUTF("UTF-32LE"));
jmethodID mid_Charset_decode = env->GetMethodID(cls_Charset, "decode", "(Ljava/nio/ByteBuffer;)Ljava/nio/CharBuffer;");
jobject cb = env->CallObjectMethod(charset, mid_Charset_decode, bb);
jclass cls_CharBuffer = env->FindClass("java/nio/CharBuffer");
jmethodID mid_CharBuffer_toString = env->GetMethodID(cls_CharBuffer, "toString", "()Ljava/lang/String;");
jstring ret = env->CallObjectMethod(cb, mid_CharBuffer_toString);
return ret;
注意:这取决于您所在平台的字节顺序。从 this answer 看来所有 Android 平台都是小端。如果您使用的是大端平台,则可能需要使用 UTF-32BE
。