如何将 buffer[] 附加到 vector<> 然后将其复制到 jbytearray?

how to append a buffer[] to a vector<> and then copy it to a jbytearray?

这会执行 sane_read(使用 SANE)并转换为 java 应用程序。

expected_bytes 可能不是 100% 准确,因此使用向量<>。

出现问题,因为生成的图像有误。如果我直接使用 env->SetByteArrayRegion 就可以了。

所以,错误在 vector<> context 上。

我做错了什么?

    long expected_bytes = pars.bytes_per_line * pars.lines *
                            ((pars.format == SANE_FRAME_RGB
                              || pars.format == SANE_FRAME_GRAY) ? 1 : 3);

    //fprintf (stderr, "Expected bytes: %ld\n", expected_bytes);

    SANE_Byte buffer[2048];
    SANE_Int bytes_read;
    vector<SANE_Byte *> data;
    data.reserve(expected_bytes);

    do {
        status = sane_read((SANE_Handle *)hnd, buffer, sizeof(buffer), &bytes_read);

        if (status != SANE_STATUS_GOOD) {
            if (status == SANE_STATUS_EOF) {
                break;
            }

            throwEx(env, getError(status));
            break;
        }

        if (bytes_read > 0) {
            data.insert(data.end(), &buffer, (&buffer) + bytes_read);
        }
    }
    while(1);

    jbyteArray bytes = env->NewByteArray(data.size());
    env->SetByteArrayRegion(bytes, 0, data.size(), (const jbyte *) &data[0]);

第一个问题是您将 data 声明为 SANE_Byte* 的向量(即指针)而不是向量 SANE_Byte(原始字符)。当您调用 SetByteArrayRegion() 时,您希望传递一个指向字符数据的指针,但实际上您传递的是一个指向指针数组的指针;这些不会产生所需的图像数据。

第二个问题是您将数据插入向量的方式:

SANE_Byte buffer[2048];
...
data.insert(data.end(), &buffer, (&buffer) + bytes_read);

由于 buffer 的类型为 SANE_Byte[2048](2048 字节的数组),这意味着 &buffer 的类型为 SANE_Byte(*)[2048](指向 2048 字节的数组的指针)。数组衰减为指向其第一个元素的指针,因此在大多数表达式上下文中,buffer&buffer 都具有等效的 ,但它们具有非常不同的类型并且不t 与指针算法一起使用时表现相同。

假设buffer分配在地址0x01000000。 buffer+1 衰减为 0x01000001,buffer+2047 衰减为数组的最后一个元素 0x010007FF。那里没有惊喜。 &buffer 也是 0x01000000,但是如果考虑表达式 (&buffer) + 1,会发生一些不同的事情:它指向缓冲区开始后的 2048 个字节.

这是内存图:

Address        +0       +1     ...    +0x7FF
           +--------+--------+-   -+-----------+
0x01000000 | buf[0] | buf[1] | ... | buf[2047] |  // This row is &buffer
           +--------+--------+-   -+-----------+
0x01000800 |   ?    |   ?    | ... |   ?       |  // This row is (&buffer) + 1
           +--------+--------+-   -+-----------+
0x01001000 |   ?    |   ?    | ... |   ?       |  // This row is (&buffer) + 2
           +--------+--------+-   -+-----------+
...            ...
           +--------+--------+-   -+-----------+
0x013FF800 |   ?    |   ?    | ... |   ?       |  // This row is (&buffer) + 2047
           +--------+--------+-   -+-----------+
0x01400000 |   ?    |   ?    | ... |   ?       |  // This row is (&buffer) + 2048
           +--------+--------+-   -+-----------+

因此,如果 sane_read() returns 一个 2048 字节的完整缓冲区,则插入到 [&buffer, (&buffer) + bytes_read) 向量的内存范围是从中读出的 4 MB 字符数据从 buffer 开始的内存区域,这是一个巨大的缓冲区溢出。然后,对 data.insert() 的调用将这 4 MB 解释为一个指针数组;如果你在 64 位系统上,那将超过 100 万个指针,其内容是未定义的。老实说,我很惊讶这没有立即崩溃。

构建向量的正确方法是将其声明为 vector<SANE_Byte> 类型(字符,而非指针),并在每次循环迭代时将每个缓冲区复制到其中。引用 buffer 的正确字节范围的方法不是使用 &buffer(&buffer) + bytes_read,而是使用 bufferbuffer + bytes_read,或者等效地 &buffer[0]&buffer[bytes_read]:

vector<SANE_Byte> data;
...
data.insert(data.end(), buffer, buffer + bytes_read);