dooplaye
dooplaye

Reputation: 1029

Convert jcharArray to String with right encoding jni

I have native method that return array of files in directory. public static native char[][] scan(String path); I can't return array of strings because if file has invalid encoding- everything crashes The problem is correctly convert char[] to String on java side, when i try new String(chars); i get unprintable string (invalid). Please correct me.

Here is example of output (If method return String[])

Array.toString(scan("/storage/")); -> [/storage/sdcard1, /storage/sdcard0]

Here is if method return char[][];

char[][] chars = scan("/storage/");
String[] stringArray = new String[char.length];
for(int i = 0; i < chars.length; i++){
    stringArray[i] = new String(char[i]);
}
Arrays.toString(stringArray); -> //unprintable symbols [����������爀条⽥摳慣摲쉮R����,����������爀条⽥摳慣摲쉮R����]

What happens on C side: if method return String[]

jobjectArray scan(JNIEnv *env, jclass cls,jstring jpath){
    std::vector<std::string> data;//contains some strings
    unsigned int size = data.size();
    jobjectArray ret = env->NewObjectArray(size,env->FindClass("java/lang/String"),NULL);
    for (unsigned int i = 0; i < size; i++){
            env->SetObjectArrayElement(ret,i,env->NewStringUTF(data.at(i).c_str()));
        }
    return ret;
}

What happens on C side: if method return char[][];

jobjectArray scan(JNIEnv *env, jclass cls,jstring jpath){
        std::vector<std::string> data;//contains some strings
        unsigned int size = data.size();
        jobjectArray ret = env->NewObjectArray(size, env->FindClass("[C"), NULL);
        for (unsigned int i = 0; i < size; i++){
                env->SetObjectArrayElement(ret,i,env->NewStringUTF(toChar(env,data.at(i))));
            }
        return ret;
    }
    jcharArray toChar(JNIEnv *env, string string) {
        unsigned int n=0;
        const char* p = string.c_str();
        while(*p++){
            n++;
        } if(n<=0)
            return NULL;

        jcharArray arr = env->NewCharArray(n);
        env->SetCharArrayRegion(arr,0,n, (jchar*)p);
        return arr;
    }

Upvotes: 0

Views: 1280

Answers (1)

fadden
fadden

Reputation: 52313

You can't use NewStringUTF on non-MUTF8 strings (where MUTF8 is the "modified UTF-8" defined by the JNI spec).

You either need to convert the local character set to UTF-16 in native code and then use NewString, or pass arrays of byte[] into your Java code and then use the String constructor that takes a charset argument. The Charset to use depends on what your filesystem supports.

Right now you're either putting non-MUTF8 data into NewStringUTF, which will fail noisily if CheckJNI is enabled, or you're putting byte values into UTF-16 chars without doing a charset conversion.

Upvotes: 2

Related Questions