NewString () and NewStringUTF (), showing that the error is not valid. Modified UTF-8:

I am trying to transfer char*

from C ++ to java using JNI in android. I tried several ways to pass this data

1) Using NewStringUTF

:

const char* data = getData(); // this method returns a char array.
env->NewStringUTF(data);

      

Executing above code throws below error

JNI WARNING: input is not valid Modified UTF-8: illegal continuation byte 0x70.

      

2) Using NewString

:

const char* data = getData(); // this method returns a char array.
// passing a byte array to java
jbyteArray trackIDArray = env->NewByteArray(strlen(data));
env->SetByteArrayRegion(trackIDArray, 0, strlen(data), (const jbyte*)trackID);

      

On the java side, I am getting some garbage value. I don't understand how to get this array char

in Java.

+4


source to share


4 answers


1) yours is data

just not a valid UTF-8 string. Not every char array is automatically valid UTF-8. You are probably using it as a single byte encoding (like ISO or Windows CP), or not reading the string at all.

2) should be ok, but show the code that fills in trackID

from data

. The fact that you need to hard-code it to jbyte*

is suspicious. This code may be correct, but you could also be wrong on the Java side:



If data

it is not a readable string, or is in a single byte encoding that is not the "platform default" java.lang.String (byte []) the constructor cannot make it a human readable string! In this case, you should switch to UTF-8 on the C side. You will also free yourself from the dependency on platform-specific encoding (which may be completely different).

+2


source


I would suggest data

instead trackID

.

env->SetByteArrayRegion(trackIDArray, 0, strlen(data), (const jbyte*)data);

      

Then you have bytes, and on the java side what encoding might look like - with a hex dump or some other inspection.



Further:

String s = new String(data, "Cp1252"); // Or so.

      

+2


source


NewStringUTF expects you to pass a modified UTF-8 string. You are probably trying to stream UTF-8.

There are several ways to fix this: The most obvious is to encode the string for UTF-8, changed to C ++, before transferring it to Java.

Another way is to pass it to Java as a byte array and use the String constructor to convert it from UTF-16.

The second way might be more efficient since at the end Java uses UTF-16 to represent strings.

As an alternative approach, you can convert the string to UTF-16 in C ++ and pass it to the JNI newString function, which expects UTF-16.

+2


source


I have put very large byte sources (> 1KB) behind the JNI like this:

std::string data1 =
#include "big_table1.csv"
;

std::string data2 =
#include "big_table2.csv"
;

extern "C" JNIEXPORT jbyteArray JNICALL
Java_com_example_bigData_rawResource(
        JNIEnv *env,
        jobject /* this */, jint index) {

    std::string values;

    switch (index) {
        case 0: {values = data1;break;}
        case 1: {values = data2;break;}
    }

    int byteCount = values.length();
    jbyteArray ret = env->NewByteArray(byteCount);
    const jbyte* pNativeMessage = reinterpret_cast<const jbyte*>(values.c_str());
    env->SetByteArrayRegion (ret, 0, byteCount, pNativeMessage);
    return ret;
}

      

In Java, you can get it back so that it is up to you to import the native function:

ByteArrayInputStream bis = null;
try {

   bis = new ByteArrayInputStream(rawResource(1);
} catch (Exception e) {
   e.printStackTrace();
}
BufferedReader buffer = new BufferedReader(new InputStreamReader(bis,   Charset.forName("UTF-8")));

      

To deal with a buffered reader is up to you too, a small example:

Strig line = buffer.readLine(); 
while ((line = buffer.readLine()) != null) {
 //play around with 'line'
}

      

0


source







All Articles