简体   繁体   English

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

[英]Return a string from JNI (C++) code to Java

Java Code: 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);
    }
}

This is my native function (C++) 这是我的本机函数(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;
}

My goal: 我的目标:

Have the native function in C++ read the contents of ram and then return it as a string or as a char array to java for further processing. 让C ++中的本机函数读取ram的内容,然后将其作为字符串或char数组返回给Java,以进行进一步处理。

Problem: 问题:

The return value of the jstring result is not what I expected it to be in java, there are several problems, first of all it has a length of 7 instead of 4096 as was intended. jstring result的返回值不是我在Java中期望的值,存在几个问题,首先它的长度为7而不是预期的4096。 Antoher problem is the output is nonsensical. 另一个问题是输出没有意义。 I have another program written in C++ which basically reads the contents of the RAM and then just prints them to a console. 我有另一个用C ++编写的程序,该程序基本上读取RAM的内容,然后将它们打印到控制台。 Here is the code bellow it works like a charm.I know from which address to read and I know what result to expect, and it does work without any problems so long as I am using C++ but as soon as I use JNI with the same methods before mentioned problems occur. 这是下面的代码,它就像一个魅力一样工作。我知道从哪个地址读取数据,也知道预期的结果,只要我使用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;
}

What I have tried thus far: 到目前为止我尝试过的是:

Check list 1. Not a permission problem 2. Ram address is correct and I know what is stored there. 检查清单1.不是权限问题2. Ram地址正确,我知道那里存储了什么。 How do I know? 我怎么知道? I am reading RAM of a calculator, and I am looking for a specific set of numbers that I type in. With C++ I find them, but with jni not really. 我正在读取计算器的RAM,并且正在寻找要键入的一组特定数字。使用C ++可以找到它们,但是使用jni却不是。 3. Read more about UTF_8 and UTF_16 (there is a good chance the problem is here) 4. Seen posts here tried to reproduce the solutions, but to no avail. 3.阅读有关UTF_8和UTF_16的更多信息(这里很可能出现问题)。4.此处看到的帖子试图重现解决方案,但无济于事。

OS: Linux 64 bit Fedora 操作系统:Linux 64 bit Fedora

Question: 题:

How to convert a C++ string to a jstring and then return it in java and print it out so that the output would match the output of the C++ program listed above has. 如何将C ++字符串转换为jstring,然后在java中返回并打印出来,以使输出与上面列出的C ++程序的输出匹配。

Anyway this is how I intended to go about solving it, but if anyone has any better solutions or just functional solutions, I will more then gladly accept them. 无论如何,这就是我打算解决的方式,但是如果有人有更好的解决方案或只是功能性解决方案,那么我将更乐于接受它们。

Then you all for your time and effort. 然后,您全都需要您的时间和精力。

JNI stores strings in modified utf-8 encoding (see bottom of the page). JNI以修改后的utf-8编码存储字符串(请参阅页面底部)。

If you want to keep using String, then you have to convert your bytes into this modified utf-8 encoding (so byte values >127 and zero have to be converted into 2 bytes). 如果要继续使用String,则必须将字节转换为这种修改的utf-8编码(因此,字节值> 127和零必须转换为2个字节)。

But as Jorn suggested in the comments, you'll want to use ByteBuffer or a simple byte array ( byte[] ) instead, as it is more optimal: with String , you waste memory, as it contains 16-bit elements. 但是正如Jorn在评论中所建议的那样,您将要使用ByteBuffer或简单的字节数组( byte[] ),因为它是最佳选择:使用String会浪费内存,因为它包含16位元素。

I managed to get it to work but it took some tinkering. 我设法使其正常工作,但花了一些时间进行修补。 Here is the code bellow which can be combined with the original code I have posted Many thx to all, I will try to up vote the answers. 这是下面的代码,可以与我发布的原始代码结合使用。非常感谢,我将尝试对答案进行投票。

In the main inside of Java code simply create this to convert the byte array into human readable chars. 在Java代码的主要内部,只需创建此代码即可将字节数组转换为人类可读的字符。 Keynote, not all chars will be properly converted but as far as my tests go all special chars such as !"£$%^&*()_+=-{}[]@~:;'#<>?,./ will be printed out no problems plus letters and numbers AZ az 0-9 anything else if you have some letters outside of English alphabet or something like that, you're likely to have problems. 主题演讲,并不是所有的字符都会被正确转换,但是就我的测试而言,所有特殊字符都可以转换,例如!“£$%^&*()_ + =-{} [] @〜:;'#<>?,.。 /将会打印出来,没有问题,再加上字母和数字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);

    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM