当四字节UTF-8遇上JNI

简介:

android在Java层对 utf 编码是支持得很好了,非常全面;但当你从事一些c/c++工程的开发时可就没有这么幸运了。 笔者最近在使用v8 javascript 引擎时便碰到了一个问题:

有些用户在昵称中使用了 emoji 表情,v8 引擎内部默认会使用utf-16编码,通过 v8 API 取到这个值之后转为utf-8的字符串,进而通过 JNI 的 API JNIEnv->NewStringUTF 往 Java 传递时会被系统的 checkJNI 给拦截住而报错。原因在为了让字符串中不包含任何 null 字节,JNI 以及 Java VM 内部都是使用的Modified UTF-8格式来编码字符串。

后来找到一个办法可以通过将字符串转为 utf-16 编码后传递给 JNI API JNIEnv->NewString 解决之:

  1. 使用 v8 API 将 utf-8 的字符串转为 utf-16 编码
    size_t utf8_to_utf16(const char *src, const uint16_t **dest) {
        if (src == NULL || dest == NULL) {
            return 0;
        }
        Isolate::Scope scope(Isolate::GetCurrent());
        HandleScope handle_scope;
        Local<String> str = String::New(src);
        String::Value val(str); // String::Value的内部编码是 utf-16
        const size_t len = (val.length()) * sizeof(uint16_t);
        uint16_t* target = (uint16_t*)calloc(val.length() + 1, sizeof(uint16_t));
        if (target == NULL) {
            return 0;
        }
        memcpy(target, *val, len);
        *dest = target;
        return val.length();
    }
    
  2. 将生成的 utf-16 字符串通过 JNI 传递到 Java 层
    uint16_t *utf16_action = NULL;
    size_t len = utf8_to_utf16(action, &utf16_action);
    jstring jText = (*env)->NewString(env, utf16_action, len);
    if (utf16_action != NULL) {
        free(utf16_action);
    }
    if (len == 0) {
        jText = (*env)->NewStringUTF(env, ""); // 降级到使用NewStringUTF来创建一个""字符串
    }
    

另外一种解决方法是通过 byteArray 来将 utf-8 编码的字符串传送到java层,

目录
相关文章
|
4月前
|
Java
Java系列之:字符串UTF-8 编码格式转换位 UTF-32 【生僻字截取问题】
这篇文章讨论了在Java中处理包含生僻字的字符串时可能遇到的问题,并提供了一种解决方法:将字符串的编码格式从UTF-8转换为UTF-32,以确保每个字符都占用固定的字节数,从而避免在截取操作中破坏字符,示例代码展示了如何进行编码转换和字符串截取。
|
4月前
|
自然语言处理
字符编码问题之UTF-16不直接采用4字节定长编码来支持所有字符如何解决
字符编码问题之UTF-16不直接采用4字节定长编码来支持所有字符如何解决
49 0
|
自然语言处理 Java 索引
Java中的Unicode字符编码与占用比特位解析
Java中的Unicode字符编码与占用比特位解析
|
存储
编码集的作用是什么?说出几个常见的编码集?为什么常用utf-8?
编码集的作用是什么?说出几个常见的编码集?为什么常用utf-8?
127 0
|
存储
4.编码集的作用是什么?说出几个常见的编码集?为什么常用utf-8?
4.编码集的作用是什么?说出几个常见的编码集?为什么常用utf-8?
80 0
|
存储 Windows
“浅入深处“编码历史,字符串编码(ASCII, GBK, ANSI, Unicode, UTF-8编码),为什么记事本默认ANSI编码,Unicode和UTF8有什么区别
“浅入深处“编码历史,字符串编码(ASCII, GBK, ANSI, Unicode, UTF-8编码),为什么记事本默认ANSI编码,Unicode和UTF8有什么区别
144 0
|
Java 编译器 C++
编码 GBK 的不可映射字符——【java菜鸟成长记】
编码 GBK 的不可映射字符——【java菜鸟成长记】
213 0
编码 GBK 的不可映射字符——【java菜鸟成长记】
|
存储 Java Windows
java字符集(编码与解码)--计算机翻译官
计算机底层是不能直接存储字符的,只能通过一串的0和1去储存,这些0和1组合起来的就是字符集。
117 0
|
Java
Java工程编码格式由GBK转化成utf-8(编码格式互转)
Java工程编码格式由GBK转化成utf-8(编码格式互转)
486 0
Java工程编码格式由GBK转化成utf-8(编码格式互转)