Reputation: 305
I am trying to pass char*
from C++ to java using JNI in android.
I have tried number of ways to pass that 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 java side, I am getting some garbage value. I don't understand how to get this char
array to Java.
Upvotes: 4
Views: 12217
Reputation: 726
I put very big bytesources (>2kbyte) behind the JNI like this :
Content of a csv-table:
R"xxx(tbl_Cbla,Column 02,Column 03,Column 04 sdfsdsad,sdfasd,dsfaddf,fdsasdf,fafasa 18,1,10,8,0)xxx"`
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 like this, to import the native function is up to you:
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 to handle the buffered reader is also up to you, small exg.:
Strig line = buffer.readLine();
while ((line = buffer.readLine()) != null) {
//play around with 'line'
}
Upvotes: 0
Reputation: 919
NewStringUTF expects you to pass a Modified UTF-8 string. You are likely trying to pass UTF-8.
There are multiple ways to fix it: Most obvious one is to encode the string to UTF-8 modified in C++ before passing it to Java.
Another way is to pass it to Java as a byte array and use String constructor to convert it from UTF-16.
The second way might be more efficient as in the end Java uses UTF-16 for string representation.
As an alternative approach, you could convert the string to UTF-16 in C++ and pass it to newString JNI function which expects UTF-16.
Upvotes: 3
Reputation: 109597
I would suspect data
instead of trackID
.
env->SetByteArrayRegion(trackIDArray, 0, strlen(data), (const jbyte*)data);
Then you have the bytes and on the java side may look what encoding it is - by a hex dump or other inspection.
Later:
String s = new String(data, "Cp1252"); // Or so.
Upvotes: 2
Reputation: 7293
1) your data
is simply not a valid UTF-8 string. Not every char array is automatically a valid UTF-8. You probably have it in some single-byte encoding (like ISO or Windows CP), or it's not a readable string at all.
2) should be ok, but show the code which fills trackID
from data
. The fact that you need to hard typecast it to jbyte*
is suspicious. This code might be correct, but you can make a mistake on Java side too:
If data
is not a readable string or is in single-byte encoding which is not "platform's default charset" java.lang.String(byte[]) constructor won't be able to make a readable string out of it! In that case, you must convert to UTF-8 on C side. You will also release yourself from the dependency on platform specific encoding (which may be wildly different).
Upvotes: 2