在尝试将一个C的字符串转到java的字串符时,出错了,提示有非法字符。感觉非常奇怪,输入的数据确定为 utf-8 格式无误,不应该会出现非法的字符呀。查看LOG 发现非法的开始字符是 0xf0 ,感觉这个更奇怪了,因为根据utf-8的定义(http://baike.baidu.com/link?url=yrMBL7jXDhKy_LCUBL5QTZgx2Io2fCqRtp0mPBTjn-ArsSnQSWPFow89OaxkS_eSuhLpMsLoOs6HegDPp_kfIa)这个开始字符是合法的。
05-20 06:13:12.103: W/dalvikvm(1210): JNI WARNING: illegal start byte 0xf0
05-20 06:13:12.103: W/dalvikvm(1210): string: '测试客户端邮件大师?????? 发自我的iPad'
05-20 06:13:12.103: W/dalvikvm(1210): in Lcom/tec/mail/core/NativeInterface;.stringFromJNI (I)Ljava/lang/String; (NewStringUTF)
05-20 06:13:12.103: I/dalvikvm(1210): "main" prio=5 tid=1 NATIVE
05-20 06:13:12.103: I/dalvikvm(1210): | group="main" sCount=0 dsCount=0 obj=0xb6054c38 self=0x8e4ee48
05-20 06:13:12.103: I/dalvikvm(1210): | sysTid=1210 nice=0 sched=0/0 cgrp=[fopen-error:2] handle=-2145907712
05-20 06:13:12.103: I/dalvikvm(1210): at com.tec.mail.core.NativeInterface.stringFromJNI(Native Method)
05-20 06:13:12.103: I/dalvikvm(1210): at com.tec.mail.MainActivity$1.onClick(MainActivity.java:27)
05-20 06:13:12.103: I/dalvikvm(1210): at android.view.View.performClick(View.java:2485)
05-20 06:13:12.103: I/dalvikvm(1210): at android.view.View$PerformClick.run(View.java:9080)
05-20 06:13:12.103: I/dalvikvm(1210): at android.os.Handler.handleCallback(Handler.java:587)
05-20 06:13:12.103: I/dalvikvm(1210): at android.os.Handler.dispatchMessage(Handler.java:92)
05-20 06:13:12.103: I/dalvikvm(1210): at android.os.Looper.loop(Looper.java:130)
05-20 06:13:12.103: I/dalvikvm(1210): at android.app.ActivityThread.main(ActivityThread.java:3683)
05-20 06:13:12.103: I/dalvikvm(1210): at java.lang.reflect.Method.invokeNative(Native Method)
05-20 06:13:12.103: I/dalvikvm(1210): at java.lang.reflect.Method.invoke(Method.java:507)
05-20 06:13:12.103: I/dalvikvm(1210): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
05-20 06:13:12.103: I/dalvikvm(1210): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
05-20 06:13:12.103: I/dalvikvm(1210): at dalvik.system.NativeStart.main(Native Method)
05-20 06:13:12.103: E/dalvikvm(1210): VM aborting
(百度一下你就知道)导出这一错误是在android中chechjni.c里面的函数 checkUtfString;这个函数会对字符串进行检查,不符合它的标准就回出错。
源码如下:
/*
* Verify that "bytes" points to valid "modified UTF-8" data.
*/
static void checkUtfString(JNIEnv* env, const char* bytes, bool nullOk,
const char* func)
{
const char* origBytes = bytes;
if (bytes == NULL) {
if (!nullOk) {
LOGW("JNI WARNING: unexpectedly null UTF string/n");
goto fail;
}
return;
}
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.
*/
LOGW("JNI WARNING: illegal start byte 0x%x/n", utf8);
goto fail;
}
case 0x0e: {
// Bit pattern 1110, so there are two additional bytes.
utf8 = *(bytes++);
if ((utf8 & 0xc0) != 0x80) {
LOGW("JNI WARNING: illegal continuation byte 0x%x/n", utf8);
goto fail;
}
// 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) {
LOGW("JNI WARNING: illegal continuation byte 0x%x/n", utf8);
goto fail;
}
break;
}
}
}
return;
fail:
LOGW(" string: '%s'/n", origBytes);
showLocation(dvmGetCurrentJNIMethod(), func);
abortMaybe();
}
根据提示:Note: 1111 is valid for normal utf-8, but not the modified utf-8 used here.
原来是Google的utf-8是经过修改过的,对一些utf-8字符不兼容。虽然0xf0是合法的utf-8字符,但是修改后utf-8不使用这个字符
相关知识:
是否进行checkjni检查是由ro.kernel.android.checkjni决定。
在eng版本中ro.kernel.android.checkjni=1.而在user版本不做检查
解决方案:
一:
http://blog.csdn.net/livingpark/article/details/6050478
解决方法是使用字符串之前进行转换,使字符串符合要求,以下函数是一种方案,根据checkUtfString函数改写。
int char2UTF(char* cp)
{
char* bytes;
bytes = cp;
while (*bytes != '/0')
{
unsigned char 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.
*/
LOGW("JNI WARNING: illegal start byte 0x%x/n", utf8);
*((unsigned char *)(bytes-1)) = 0x3f;
break;
}
case 0x0e: {
// Bit pattern 1110, so there are two additional bytes.
utf8 = *(bytes++);
if ((utf8 & 0xc0) != 0x80) {
LOGW("JNI WARNING: illegal continuation byte 0x%x/n", utf8);
*((unsigned char *)(bytes-1)) = 0x80;
}
// 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) {
LOGW("JNI WARNING: illegal continuation byte 0x%x/n", utf8);
*((unsigned char *)(bytes-1)) = 0x80;
}
break;
}
}
}
return 0;
}
二:调用java层String的构造函数
jstring StringC2JUTF(JNIEnv* env, CString src){
int lenght = src.GetLength();
jbyteArray byteContent = env->NewByteArray(lenght * sizeof(jbyte));
env->SetByteArrayRegion(byteContent, 0, (jsize)lenght, (jbyte *)LPCSTR(src));
jclass clsString = env->FindClass("java/lang/String");
jmethodID consID = env->GetMethodID(clsString, "<init>", "([BLjava/lang/String;)V");
jobject obj = env->NewObject(clsString, consID, byteContent, env->NewStringUTF("utf-8"));
return (jstring)obj;
}
05-20 06:13:12.103: W/dalvikvm(1210): JNI WARNING: illegal start byte 0xf0
05-20 06:13:12.103: W/dalvikvm(1210): string: '测试客户端邮件大师?????? 发自我的iPad'
05-20 06:13:12.103: W/dalvikvm(1210): in Lcom/tec/mail/core/NativeInterface;.stringFromJNI (I)Ljava/lang/String; (NewStringUTF)
05-20 06:13:12.103: I/dalvikvm(1210): "main" prio=5 tid=1 NATIVE
05-20 06:13:12.103: I/dalvikvm(1210): | group="main" sCount=0 dsCount=0 obj=0xb6054c38 self=0x8e4ee48
05-20 06:13:12.103: I/dalvikvm(1210): | sysTid=1210 nice=0 sched=0/0 cgrp=[fopen-error:2] handle=-2145907712
05-20 06:13:12.103: I/dalvikvm(1210): at com.tec.mail.core.NativeInterface.stringFromJNI(Native Method)
05-20 06:13:12.103: I/dalvikvm(1210): at com.tec.mail.MainActivity$1.onClick(MainActivity.java:27)
05-20 06:13:12.103: I/dalvikvm(1210): at android.view.View.performClick(View.java:2485)
05-20 06:13:12.103: I/dalvikvm(1210): at android.view.View$PerformClick.run(View.java:9080)
05-20 06:13:12.103: I/dalvikvm(1210): at android.os.Handler.handleCallback(Handler.java:587)
05-20 06:13:12.103: I/dalvikvm(1210): at android.os.Handler.dispatchMessage(Handler.java:92)
05-20 06:13:12.103: I/dalvikvm(1210): at android.os.Looper.loop(Looper.java:130)
05-20 06:13:12.103: I/dalvikvm(1210): at android.app.ActivityThread.main(ActivityThread.java:3683)
05-20 06:13:12.103: I/dalvikvm(1210): at java.lang.reflect.Method.invokeNative(Native Method)
05-20 06:13:12.103: I/dalvikvm(1210): at java.lang.reflect.Method.invoke(Method.java:507)
05-20 06:13:12.103: I/dalvikvm(1210): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
05-20 06:13:12.103: I/dalvikvm(1210): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
05-20 06:13:12.103: I/dalvikvm(1210): at dalvik.system.NativeStart.main(Native Method)
05-20 06:13:12.103: E/dalvikvm(1210): VM aborting
(百度一下你就知道)导出这一错误是在android中chechjni.c里面的函数 checkUtfString;这个函数会对字符串进行检查,不符合它的标准就回出错。
源码如下:
/*
* Verify that "bytes" points to valid "modified UTF-8" data.
*/
static void checkUtfString(JNIEnv* env, const char* bytes, bool nullOk,
const char* func)
{
const char* origBytes = bytes;
if (bytes == NULL) {
if (!nullOk) {
LOGW("JNI WARNING: unexpectedly null UTF string/n");
goto fail;
}
return;
}
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.
*/
LOGW("JNI WARNING: illegal start byte 0x%x/n", utf8);
goto fail;
}
case 0x0e: {
// Bit pattern 1110, so there are two additional bytes.
utf8 = *(bytes++);
if ((utf8 & 0xc0) != 0x80) {
LOGW("JNI WARNING: illegal continuation byte 0x%x/n", utf8);
goto fail;
}
// 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) {
LOGW("JNI WARNING: illegal continuation byte 0x%x/n", utf8);
goto fail;
}
break;
}
}
}
return;
fail:
LOGW(" string: '%s'/n", origBytes);
showLocation(dvmGetCurrentJNIMethod(), func);
abortMaybe();
}
根据提示:Note: 1111 is valid for normal utf-8, but not the modified utf-8 used here.
原来是Google的utf-8是经过修改过的,对一些utf-8字符不兼容。虽然0xf0是合法的utf-8字符,但是修改后utf-8不使用这个字符
相关知识:
是否进行checkjni检查是由ro.kernel.android.checkjni决定。
在eng版本中ro.kernel.android.checkjni=1.而在user版本不做检查
解决方案:
一:
http://blog.csdn.net/livingpark/article/details/6050478
解决方法是使用字符串之前进行转换,使字符串符合要求,以下函数是一种方案,根据checkUtfString函数改写。
int char2UTF(char* cp)
{
char* bytes;
bytes = cp;
while (*bytes != '/0')
{
unsigned char 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.
*/
LOGW("JNI WARNING: illegal start byte 0x%x/n", utf8);
*((unsigned char *)(bytes-1)) = 0x3f;
break;
}
case 0x0e: {
// Bit pattern 1110, so there are two additional bytes.
utf8 = *(bytes++);
if ((utf8 & 0xc0) != 0x80) {
LOGW("JNI WARNING: illegal continuation byte 0x%x/n", utf8);
*((unsigned char *)(bytes-1)) = 0x80;
}
// 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) {
LOGW("JNI WARNING: illegal continuation byte 0x%x/n", utf8);
*((unsigned char *)(bytes-1)) = 0x80;
}
break;
}
}
}
return 0;
}
二:调用java层String的构造函数
jstring StringC2JUTF(JNIEnv* env, CString src){
int lenght = src.GetLength();
jbyteArray byteContent = env->NewByteArray(lenght * sizeof(jbyte));
env->SetByteArrayRegion(byteContent, 0, (jsize)lenght, (jbyte *)LPCSTR(src));
jclass clsString = env->FindClass("java/lang/String");
jmethodID consID = env->GetMethodID(clsString, "<init>", "([BLjava/lang/String;)V");
jobject obj = env->NewObject(clsString, consID, byteContent, env->NewStringUTF("utf-8"));
return (jstring)obj;
}