4-байтовое преобразование wchar_t в строку с использованием JNI - PullRequest
1 голос
/ 24 января 2020

поэтому у меня есть CanvasView, который показывает отладочную информацию моего приложения. Это в основном наложенный вид с прозрачным фоном, поэтому все нарисованное на холсте плавает на экране. Поскольку мне нужна некоторая информация из нативного c ++, которая возвращает wchar_t *, как я могу использовать 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 в основном возвращает строку jstring, полученную из NewString((const jchar* )myWchar, myLen)

Возвращаемые результаты иногда не являются строкой Unicode, или даже мое приложение аварийно завершает работу, когда NewString называется.

Ответы [ 2 ]

1 голос
/ 24 января 2020

Сначала выделите ByteBuffer, используя JNI:

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;

Примечание: это зависит от порядковый номер платформы, на которой вы находитесь. Из этого ответа кажется, что все Android платформы имеют порядок байтов. Возможно, вам придется использовать UTF-32BE вместо этого, если вы находитесь на платформе с прямым порядком байтов.

0 голосов
/ 24 января 2020

Единственная платформа, где wchar_t равен 2 байта, это Windows. На других платформах wchar_t составляет 4 байта. env->NewString() принимает данные UTF-16 в качестве входных данных, поэтому вам придется преобразовать данные wchar_t из UTF-32 в UTF-16 перед вызовом env->NewString(). В противном случае вам придется использовать JNI для вызова конструктора Java String, который принимает массив и кодировку byte[] в качестве входных данных, поэтому вы можете создать строку непосредственно из данных UTF-32.

...