如何将 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
,而是使用 buffer
到 buffer + bytes_read
,或者等效地 &buffer[0]
到 &buffer[bytes_read]
:
vector<SANE_Byte> data;
...
data.insert(data.end(), buffer, buffer + bytes_read);
这会执行 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
,而是使用 buffer
到 buffer + bytes_read
,或者等效地 &buffer[0]
到 &buffer[bytes_read]
:
vector<SANE_Byte> data;
...
data.insert(data.end(), buffer, buffer + bytes_read);