Erste echte UTF-8-Zeichen in Java-JNI

Gibt es eine einfache Möglichkeit zur Konvertierung einer Java-string zu einem echten UTF-8-byte-array im JNI code?

Leider GetStringUTFChars() fast tut, was erforderlich ist, aber nicht ganz, es gibt eine "modifizierte" UTF-8-byte-Sequenz. Der Hauptunterschied ist, dass eine modifizierte UTF-8 enthält keine null-Zeichen (so dass Sie behandeln können, ist eine ANSI-C-null-terminated string), sondern ein anderer Unterschied scheint zu sein, wie Unicode-Sonderzeichen wie emoji behandelt werden.

Ein Zeichen wie U+1F604 "LÄCHELNDES GESICHT MIT OFFENEM MUND UND LÄCHELNDEN AUGEN" gespeichert ist, als ein Surrogat-paar (zwei UTF-16-Zeichen U+D83D U+DE04) und hat einen 4-byte-UTF-8 äquivalent F0 9F 98 84, und das ist die byte-Sequenz, die ich bekomme, wenn ich konvertieren Sie die Zeichenfolge in UTF-8 in Java:

    char[] c = Character.toChars(0x1F604);
    String s = new String(c);
    System.out.println(s);
    for (int i=0; i<c.length; ++i)
        System.out.println("c["+i+"] = 0x"+Integer.toHexString(c[i]));
    byte[] b = s.getBytes("UTF-8");
    for (int i=0; i<b.length; ++i)
        System.out.println("b["+i+"] = 0x"+Integer.toHexString(b[i] & 0xFF));

Der obige code druckt die folgenden:

?
c[0] = 0xd83d
c[1] = 0xde04
b[0] = 0xf0
b[1] = 0x9f
b[2] = 0x98
b[3] = 0x84

Allerdings, wenn ich pass 's' in eine native JNI-Methode, und rufen GetStringUTFChars() bekomme ich 6 bytes. Jeder der die ersatzzeichenpaare wird umgebaut zu einem 3-byte-Sequenz unabhängig:

JNIEXPORT void JNICALL Java_EmojiTest_nativeTest(JNIEnv *env, jclass cls, jstring _s)
{
    const char* sBytes = env->GetStringUTFChars(_s, NULL);
    for (int i=0; sBytes[i]!=0; ++i)
        fprintf(stderr, "%d: %02x\n", i, sBytes[i]);
    env->ReleaseStringUTFChars(_s, sBytes);
    return result;
}

0: ed
1: a0
2: bd
3: ed
4: b8
5: 84

Den Wikipedia UTF-8 Artikel deutet darauf hin, dass GetStringUTFChars() eigentlich zurück CESU-8 anstatt UTF-8. Das wiederum bewirkt, dass meine native Mac-code zum Absturz bringen, weil es keine gültige UTF-8-Sequenz:

CFStringRef str = CFStringCreateWithCString(NULL, path, kCFStringEncodingUTF8);
CFURLRef url = CFURLCreateWithFileSystemPath(NULL, str, kCFURLPOSIXPathStyle, false);

Ich nehme an, ich könnte alle meine JNI-Methoden nehmen ein byte[] statt String und tun die UTF-8 Konvertierung in Java, aber das scheint ein bisschen hässlich, gibt es eine bessere Lösung?

InformationsquelleAutor Rolf | 2015-08-25
Schreibe einen Kommentar