Java JNI の GetStringUTFChars は古い Unicode 仕様のシーケンスを返す

Unicode サロゲートペア範囲の "𡈽" という文字は、コードポイントが U+0002123D、UTF-8 のシーケンスだと [F0, A1, 88, BD] になる。

JNI で "𡈽" のみで構成される String を以下のように UTF-8 に変換すると:

    const char *utf8 = env->GetStringUTFChars(text, NULL);

得られるシーケンスは [ED, A1, 84, ED, B8, BD] となる。

[ED, Ax, xx] と [ED, Bx, xx] はそれぞれ、サロゲートペアの上位と下位の UTF-8 表現だが、これは CESU-8 (Compatibility Encoding Scheme for UTF-16: 8-Bit) というサロゲートペアのまま UTF-8 に符号化してしまう仕様で、特に Oracle がこの方式の符号化を(データベースや結果的に Java で)採用してしまっている。

Scintilla は [F0, A1, 88, BD] しか正しい UTF-8 シーケンスとして解釈できない。秀丸なら [F0, A1, 88, BD] も [ED, A1, 84, ED, B8, BD] も同様に扱え、[F0, A1, 88, BD] に正規化される。


なお、Java で以下のように
"𡈽".getBytes("UTF-8");
するなら、[F0, A1, 88, BD] が返される。