Comparing a jbytearray with a string in JNI - android

I have a JNI C function that has an jbyteArray input parameter. This is a byte array of size 128 that I wish to compare with a #define string. How do I achieve this?
I tried to memcpy the jbyteArray to an unsigned char data[128] and then do a memcmp() of data and the #define, but the memcpy crashed my app.
Thanks.

You can use GetByteArrayElements() to get the byte array contents and then compare using strncmp or memcmp or whatever:
#define COMPARE_STRING "somestring" // can be up to 128 bytes long
// JNIEnv *pEnv
// jbyteArray byteArray
// get the byte array contents:
jbyte* pBuf = (jbyte*)(*pEnv)->GetByteArrayElements(pEnv, byteArray, 0);
if(pBuf)
{
// compare up to a maximum of 128 bytes:
int result = strncmp((char*)pBuf, COMPARE_STRING, 128);
}

I ended up copying the jbytearray using GetByteArrayRegion instead.

Related

JNI - transfer from jstring to byte, from byte to string issue

I have a problem with converting in JNI.
In C++ I'm creating some cipher using AES (Library CryptoPP). I'm converting result to string and returning it. This is how the code getting the string looks like:
JNIEXPORT jbyteArray JNICALL Java_com_example_androidake_MutualAuthenticateChip_prepareEncryptionCPP
(JNIEnv *env, jobject thisObj, jboolean hmm, jboolean jinit) {
string encryption= mac->EncryptCertKey();
jbyteArray returns = env->NewByteArray(encryption.size());
env->SetByteArrayRegion(returns, 0, encryption.length(), (jbyte*) encryption.c_str());
return returns;
};
Above string is converting to jbyteArray which is returned. First I wanted just return string using
env->NewStringUTF(encryption.c_str());
but the application has been crashing. I think it is caused by content of variable 'encryption'. I'm using env->NewStringUTF(encryption.c_str()); in other functions, where returned string is for example just a number or something like that.
Then in Java I'm doing conversion from byte to string:
byte[] cipher = mac_A.prepareEncryptionCPP(true, true);
string cipher_str = new String(cipher);
And I'm putting that string again to the C++ object and compare old cipher with the cipher which is sent from Java:
//Java
boolean result = mac_A.compareEncryption(true, cipher);
//JNI
JNIEXPORT jboolean JNICALL Java_com_example_androidake_MutualAuthenticateChip_compareEncryption
(JNIEnv * env, jobject thisObj, jboolean jinit, jstring cipher){
bool init = jinit;
bool result;
jsize length = env->GetStringUTFLength(cipher);
const char *inCStr_ek = env->GetStringUTFChars(cipher, 0);
string s(inCStr_ek, length);
result = mac->CompareCipher(s);
env->ReleaseStringUTFChars(cipher, inCStr_ek);
return result;
};
Comparing in C++ :
bool MyClass::CompareCipher(std::string cipher_2){
if(cipher == cipher_2){
return true;
}else{
return false;
}
}
And it always returns false. I do not know what I'm doing wrong. I've even sent this cipher from Java to C++ and take it back to Java and the strings are equals, but in C++ side are not.
on your java side code you have
byte[] cipher = mac_A.prepareEncryptionCPP(true, true);
boolean result = mac_A.compareEncryption(true, cipher);
compareEncryption jni function is defined with jstring , not jbytearray.
So from JNI side you are sending a byte array to java, and from java side you send back the same byte array to native side (but uses jstring in call), but then you are using env->GetStringUTFChars(cipher, 0) which converts that byte array into a modified UTF-8 string, so its technically not that same byte array anymore.
if you need strings do the conversions in java side, and just use with same plain byte arrays between jni and java. See this for string encoding issues in Android JNI.

How to copy decoded frame from C to Android

I used ffmpeg library to decode the video and got a frame buffer data.
I want to copy the frame buffer into Android byte array (format is RGB565).
How to copy the frame buffer data from C into Android byte array?
Have any one can give me some example or advice?
You could use java.nio.ByteBuffer for that:
ByteBuffer theVideoFrame = ByteBuffer.allocateDirect(frameSize);
...
CopyFrame(theVideoFrame);
And the native code could be something like:
JNIEXPORT void JNICALL Java_blah_blah_blah_CopyFrame(JNIEnv *ioEnv, jobject ioThis, jobject byteBuffer)
{
char *buffer;
buffer = (char*)(ioEnv->GetDirectBufferAddress(byteBuffer));
if (buffer == NULL) {
__android_log_write(ANDROID_LOG_VERBOSE, "foo", "failed to get NIO buffer address");
return;
}
memcpy(buffer, theNativeVideoFrame, frameSize);
}
To copy the data from the ByteBuffer to a byte[] you'd then use something like:
theVideoFrame.get(byteArray);

A correct way to convert byte[] in java to unsigned char* in C++, and vice versa?

I'm newbie in C++ and JNI, I try to find a correct way to convert byte[] in java to unsigned char* in C++ by using JNI, and vice versa ! (I'm working on android)
After looking for a solution in google and SO, I haven't found a good details way to convert byte[] in java to C++. Please help me, and provide a solution for a vice versa (unsigned char* in C++ to byte[] in java). Thanks very much
byte[] in java to unsigned char* in C++:
JAVA :
private static native void nativeReceiveDataFromServer(byte[] value, int length);
JNI:
... (JNIEnv* env, jobject thiz, jbyteArray array, jint array_length)
{
???
}
PS: I modified my question for being a real question for my problem :(
You can use this to convert unsigned char array into a jbyteArray
jbyteArray as_byte_array(unsigned char* buf, int len) {
jbyteArray array = env->NewByteArray (len);
env->SetByteArrayRegion (array, 0, len, reinterpret_cast<jbyte*>(buf));
return array;
}
to convert the other way around...
unsigned char* as_unsigned_char_array(jbyteArray array) {
int len = env->GetArrayLength (array);
unsigned char* buf = new unsigned char[len];
env->GetByteArrayRegion (array, 0, len, reinterpret_cast<jbyte*>(buf));
return buf;
}
The array buf is a variable on stack. After leaving the function is this variable undefined.
A solution is separating this function in two, one to compute the size and another with a pointer to now the allocated array as parameter to fill in the values.

How to convert char[] to ByteBuffer in JNI?

I want to pass a ByteBuffer over JNI to C++, as the buffer to receive an image decoded from AVDecode, though the buffer is correctly filled in C++, but the ByteBuffer at the Java side is still empty.
Please help me to find out where is the error. Thanks.
pOutBuffer is the ByteBuffer passed via JNI.
jclass ByteBufferClass = env->GetObjectClass(pOutBuffer);
jmethodID ArraryMethodId = env->GetMethodID(ByteBufferClass,"array","()[B");
jmethodID ClearMethodId = env->GetMethodID(ByteBufferClass,"clear","()Ljava/nio/Buffer;");
//clear buffer
env->CallObjectMethod(pOutBuffer,ClearMethodId);
jbyteArray OutByteArrary = (jbyteArray)env->CallObjectMethod(pOutBuffer,ArraryMethodId);
jbyte OutJbyte = env->GetByteArrayElements(OutByteArrary,0);
Out = (unsigned char*)OutJbyte;
DecodeSize = AVDecode(m_pVideoDecode, (unsigned char *)In, inputSize, (unsigned char **)&Out, (int *)&pBFrameKey);
The decoding is correct and I can see that 'Out' is filled with the output image, however, when this function returns, the pOutBuffer at the Java side is still empty.
How was the ByteBuffer created? Is it a direct or non-direct ByteBuffer?
If it's a direct ByteBuffer which has been created in Java using the allocateDirect method you can us GetDirectBufferAddress in your native code to get the direct address of the ByteBuffer and any changes there should be reflected in Java.

getArrayLength() is returning a huge number...

I am trying to understand jni, so I started hacking up hellojni, and I ran into this problem.
My java code looks like this:
short[] buf = new short[16];
Log.d("hello", "before!");
write(buf, 0, 16);
and my C code looks like this:
jint
Java_com_example_hellojni_HelloJni_write(JNIEnv* env, jshortArray buf, jint off, jint len)
{
char debug[1024];
int ii = 0;
jsize cbuflen = (*env)->GetArrayLength(env, buf);
sprintf(debug, "array length: %d", cbuflen);
LOGD(debug);
...
...
The output is:
array length: 1079082088
Why is the array length so big?
Could you show your entire JNI file? You are not declaring the target object in your JNI function. Usually the arguments are JNIEnv* env, jobject javaObject, etc. This means that what you believe is the jshortArray is actually the pointer to a Java object, which would explain the weird results you are getting.

Categories

Resources