jni 中使用NewStringUTF时报错:input is not valid Modified UTF-8: illegal start byte 0xa0

本文分析了在使用Dalvik虚拟机时遇到的Modified UTF-8格式错误,并提供了通过更改char*为const char*来解决该问题的方法。

报错 :

05-20 10:35:30.702: A/art(32149): art/runtime/check_jni.cc:65] JNI DETECTED ERROR IN APPLICATION: input is not valid Modified UTF-8: illegal start byte 0xa0


原因是:定义的是char * 

解决办法:

将char * 定义更换为const char * ,即可解决问题。

分析: 

这是因为在调用NewStringUTF()时, dalvik虚拟机调用checkUtfString() 中的checkUtfBytes()对字符串的格式进行了校验.

checkUtfBytes的源码在<android-src>/dalvik/vm/CheckJni.cpp 中,如下:

    /*
     * Verify that "bytes" points to valid "modified UTF-8" data.
     */
    void checkUtfString(const char* bytes, bool nullable) {
        if (bytes == NULL) {
            if (!nullable) {
                ALOGW("JNI WARNING: non-nullable const char* was NULL (%s)", mFunctionName);
                showLocation();
                abortMaybe();
            }
            return;
        }


        const char* errorKind = NULL;
        u1 utf8 = checkUtfBytes(bytes, &errorKind);
        if (errorKind != NULL) {
            ALOGW("JNI WARNING: %s input is not valid Modified UTF-8: illegal %s byte %#x",
                  mFunctionName, errorKind, utf8);
            ALOGW("             string: '%s'", bytes);
            showLocation();
            abortMaybe();
        }
    }


static u1 checkUtfBytes(const char* bytes, const char** errorKind) {
        while (*bytes != '\0') {
            u1 utf8 = *(bytes++);
            // Switch on the high four bits.
            switch (utf8 >> 4) {
            case 0x00:
            case 0x01:
            case 0x02:
            case 0x03:
            case 0x04:
            case 0x05:
            case 0x06:
            case 0x07:
                // Bit pattern 0xxx. No need for any extra bytes.
                break;
            case 0x08:
            case 0x09:
            case 0x0a:
            case 0x0b:
            case 0x0f:
                /*
                 * Bit pattern 10xx or 1111, which are illegal start bytes.
                 * Note: 1111 is valid for normal UTF-8, but not the
                 * modified UTF-8 used here.
                 */
                *errorKind = "start";
                return utf8;
            case 0x0e:
                // Bit pattern 1110, so there are two additional bytes.
                utf8 = *(bytes++);
                if ((utf8 & 0xc0) != 0x80) {
                    *errorKind = "continuation";
                    return utf8;
                }
                // Fall through to take care of the final byte.
            case 0x0c:
            case 0x0d:
                // Bit pattern 110x, so there is one additional byte.
                utf8 = *(bytes++);
                if ((utf8 & 0xc0) != 0x80) {
                    *errorKind = "continuation";
                    return utf8;
                }
                break;
            }
        }
        return 0;
    }




C语言中,char * 、const char* 和unsigned char* 的对字符串的处理及区别和联系有待研究。

当遇到 'input is not valid Modified UTF - 8: illegal continuation byte' 错误,这通常是因为输入的字符序列不符合 Modified UTF - 8 编码规则,Regular UTF - 8 合法的编码序列在 Modified UTF - 8 可能被视为非法的 [^2]。以下是一些可能的解决办法: #### 1. 检查数据源 确保输入的数据是合法的 UTF - 8 编码。数据可能在传输或存储过程中被损坏。例如,如果数据来自文件,可使用文本编辑器检查文件编码是否为 UTF - 8,或者使用工具验证文件的编码。 #### 2. 过滤非法字符 在处理数据前,对输入数据进行过滤,移除非法的 UTF - 8 字节序列。以下是一个 Java 示例代码,用于过滤非法 UTF - 8 字符: ```java import java.nio.charset.StandardCharsets; import java.util.regex.Pattern; public class UTF8Filter { private static final Pattern INVALID_UTF8 = Pattern.compile("[^\u0000-\uD7FF\uE000-\uFFFF]"); public static String filterInvalidUTF8(String input) { return INVALID_UTF8.matcher(input).replaceAll(""); } public static void main(String[] args) { String input = "包含非法 UTF - 8 字符的字符串"; String filtered = filterInvalidUTF8(input); System.out.println(filtered); } } ``` #### 3. 处理文件遍历问题 若在文件遍历过程中出现此错误,如 `file.listFiles` 方法调用出错,可对文件路径和文件名进行编码转换或过滤。示例代码如下: ```java import java.io.File; import java.io.FilenameFilter; public class EssFileFilter implements FilenameFilter { private String[] types; public EssFileFilter(String[] types) { this.types = types; } @Override public boolean accept(File dir, String name) { try { // 过滤文件名中的非法字符 String filteredName = UTF8Filter.filterInvalidUTF8(name); for (String type : types) { if (filteredName.endsWith(type)) { return true; } } } catch (Exception e) { e.printStackTrace(); } return false; } } ``` #### 4. 检查 JNI 调用 在使用 JNI 调用,确保传递给 JNI 函数的字符串是合法的 Modified UTF - 8 编码。若可能,在 Java 端对字符串进行预处理,确保传递合法字符串给 JNI 层。 #### 5. 编码转换 尝试将数据从其他编码转换为 UTF - 8。例如,若数据原本是 GBK 编码,可使用以下 Java 代码进行转换: ```java import java.nio.charset.Charset; public class EncodingConverter { public static String convertToUTF8(String input, String originalEncoding) { byte[] bytes = input.getBytes(Charset.forName(originalEncoding)); return new String(bytes, StandardCharsets.UTF_8); } public static void main(String[] args) { String input = "原始字符串"; String converted = convertToUTF8(input, "GBK"); System.out.println(converted); } } ```
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值