将字符串从JNI(C ++)代码返回到Java

时间:2017-06-27 14:17:10

标签: java c++ java-native-interface native ram

Java代码:

public class MainClass 
{       
    static
    {
        System.load("/home/chronic/workspace/ramRead/src/libRamRead.so");
    }
    private native String readRam(int len, long addr, int pid);
    private native int readSize();

    public static void main(String[] args) 
    {
        MainClass app = new MainClass();


        String x = app.readRam(4096, 0x55c5520b5000L, 4435);

        //System.out.println("HEY THERE");
        //  System.out.println("I BEGIN HERE");
        System.out.println(x.length());

        //int test = app.readSize();
        //System.out.println(test);
    }
}

这是我的原生函数(C ++)

JNIEXPORT jstring JNICALL Java_ramRead_MainClass_readRam
  (JNIEnv *env, jobject, jint len, jlong addr, jint pid)
{
        struct iovec local[1];
        struct iovec remote[1];
        char buf[len];
        jstring result;
        //jcharArray buf = (*env).NewCharArray(len);
        //jcharArray buf1 = (*env).NewCharArray(len);

        local[0].iov_base = buf;
        local[0].iov_len = len;

        remote[0].iov_base = (void *) addr;
        remote[0].iov_len = len;

        nread = process_vm_readv(pid, local, 1, remote, 1, 0);

        //printf("len %d, pid %d, addr %li, buf %c, size of buf %d ", len, pid, addr, buf, sizeof(buf));
        printf("\nTHIS MUCH: %d\n", nread);

        for(int i=0; i<4096; i++){
                printf("%c", buf[i]);
        }

        //(*env).SetCharArrayRegion(buf1, 0, len, buf);
 result = (*env).NewStringUTF(buf);
        //printf("RESULT: %s", (*env).GetStringUTFLength(result));

        return result;
}

我的目标:

让C ++中的本机函数读取ram的内容,然后将其作为字符串或char数组返回给java进行进一步处理。

问题:

jstring result的返回值不是我在java中的预期,有几个问题,首先它的长度为7而不是4096。 Antoher问题是输出是荒谬的。我有另一个用C ++编写的程序,它基本上读取RAM的内容,然后将它们打印到控制台。下面的代码就像魅力一样。我知道要从哪个地址阅读,我知道会得到什么结果,只要我使用C ++但是只要我使用相同的JNI,它就可以正常工作前面提到的方法出现问题。

    #include <jni.h>
#include "ramRead_MainClass.h"
#include <sys/uio.h>

static ssize_t nread;

JNIEXPORT jbyteArray JNICALL Java_ramRead_MainClass_readRam
  (JNIEnv *env, jobject, jint len, jlong addr, jint pid)
//JNIEXPORT jbyteArray JNICALL Java_ramRead_MainClass_readRam
  //(JNIEnv *env, jobject, jobject len, jobject addr, jint pid)
{
        struct iovec local[1];
        struct iovec remote[1];
        jbyte buf[len];
        jbyteArray buf1 = (*env).NewByteArray(len);

        local[0].iov_base = buf;
        local[0].iov_len = len;

        remote[0].iov_base = (void *) addr;
        remote[0].iov_len = len;

        nread = process_vm_readv(pid, local, 1, remote, 1, 0);

        (*env).SetByteArrayRegion(buf1, 0, len, buf);
        return buf1;
}

JNIEXPORT jint JNICALL Java_ramRead_MainClass_readSize
  (JNIEnv *, jobject)
{
        return nread;
}

到目前为止我尝试过:

检查清单 1.不是许可问题 2. Ram地址是正确的,我知道那里存储的是什么。我怎么知道?    我正在读一个计算器的RAM,我正在寻找一些我输入的特定数字。用C ++我找到它们,但jni并不是真的。 3.阅读有关UTF_8和UTF_16的更多信息(问题很可能在这里) 这里看到的帖子试图重现解决方案,但无济于事。

操作系统:Linux 64位Fedora

问题:

如何将C ++字符串转换为jstring,然后在java中将其返回并打印出来,以便输出与上面列出的C ++程序的输出相匹配。

无论如何,这就是我打算解决它的方式,但如果有人有更好的解决方案或只是功能解决方案,我会更乐意接受它们。

然后你们都花时间和精力。

2 个答案:

答案 0 :(得分:0)

JNI将字符串存储在modified utf-8 encoding中(参见本页底部)。

如果你想继续使用String,那么你必须将你的字节转换为这个修改过的utf-8编码(所以字节值> 127,零必须转换成2个字节)。

但正如Jorn在评论中所建议的那样,您将要使用ByteBuffer或简单的字节数组(byte[]),因为它更为理想:String ,你浪费内存,因为它包含16位元素。

答案 1 :(得分:-1)

我设法让它上班,但需要一些修修补补。这是下面的代码,可以与我发布的原始代码结合使用 很多人,我会尽力投票给答案。

在Java代码的主要内部,只需创建它以将字节数组转换为人类可读的字符。主题演讲,并非所有字符都会被正确转换,但就我的测试而言,所有特殊字符都是如此!“££%^&amp; *()_ + = - {} [] @〜:;'#&lt;&gt; ?,。/将打印出来没有问题加字母和数字AZ az 0-9如果你有一些英文字母之外的字母或类似的东西,你可能会遇到问题。

public static void main(String[] args){
        MainClass app = new MainClass();

            byte[] x = app.readRam(4096, 0x556cbdb2a000L, 22444);

            System.out.println(x.length);
            System.out.write(x, 0, x.length);

            for(int i=0; i<x.length; i++)
            {   
                if((int)x[i] >= 32 && (int)x[i] < 127)
                {
                    System.out.print((char)x[i]);
                }
            }

            char c = 120;
            System.out.println("\n" + c);

    }