Swig:将返回类型std :: string(二进制)转换为java byte [] [英] Swig: convert return type std::string(binary) to java byte[]
问题描述
我的情况是我有一个C ++类(MyClass),其方法具有以下签名:
My situation is that i have a C++ class (MyClass) with a method that has the following signature:
bool getSerialized(const stdString & name, std::string & serialized);
其中name是参数,序列化是out参数。
Where name is a in argument and serialized is an out argument.
我通过在'i'文件中进行%extend和%ignore声明来实现它,如下所示:
I got it working by making a %extend and %ignore declarations in the 'i' file as follows:
%extend MyClass{
std::string getSerialized(const std::string & name){
std::string res;
$self->getSerialized(name, res);
return res;
};
%rename("$ignore", fullname=1) "MyClass::getSerialized";
因此可以使用Java中的方法:
So the method con be used from Java like:
MyClass mc = new MyClass();
String res = mc.getSerialized("test");
但是现在我遇到了一个问题,序列化的std :: string包含二进制数据,包括' \ 0'字符女巫表示C字符串的结尾,实际上下面的代码显示了C ++中的问题:
But now i have encountered a problem, the serialized std::string contains binary data, including the '\0' character witch indicates the end of a C String, in fact the following code shows the problem in C++:
std::string s;
s.push_back('H');
s.push_back('o');
s.push_back(0);
s.push_back('l');
s.push_back('a');
std::cout << "Length of std::string " << s.size() << std::endl;
std::cout << "CString: '" << s.c_str() << "'" << std::endl;
上面的代码显示:
Length of std::string 5
CString: 'Ho'
正如我在SWIG生成的包装文件中看到的那样,wrap方法实际上调用c_str(),包装代码:
As i have seen in the wrap file generated by SWIG, the wrap method actually calls c_str(), code of wrap:
jstring jresult = 0 ;
std::string result;
result = (arg1)->getSerialized();
jresult = jenv->NewStringUTF((&result)->**c_str()**);
return jresult;
正如预期的那样,Java中收到的字符串会被截断。那么我怎么能改变(大概)我的%扩展函数包装器,所以我可以将它作为字节数组(byte [])返回,而不需要事先知道数组的长度。如果可以在SWIG层中创建byteArray会很棒,所以我可以从Java调用方法,如:
So as expected the received String in Java gets truncated. So how can i change (presumably) my %extend function wrapper so i can return this as a byte array (byte[]), without previously knowing the length of the array. It would be great if the byteArray could be created in the SWIG layer, so i could invoke the method from Java like:
byte[] serialized = mc.getSerialized("test");
其他注意事项:
给出了使用std :: string存储二进制数据的方法,使用Google protobuf库的返回类型 C ++ protobuf usage
有一个非常类似的问题,包括tittle Swig:将返回类型std :: string转换为java byte [] ,但二进制数据没有任何情况,所以那里给出的解决方案没有在这里申请。
There is a very similar question, including the tittle Swig: convert return type std::string to java byte[] but there is no case for binary data, so the solution given there doesn't apply here.
使用SWIG 2.
推荐答案
你可以做您正在尝试使用一些类型映射和一些JNI。我把一个例子放在一起:
You can do what you're trying to do with a few typemaps and some JNI. I put together an example:
%module test
%include <std_string.i>
%typemap(jtype) bool foo "byte[]"
%typemap(jstype) bool foo "byte[]"
%typemap(jni) bool foo "jbyteArray"
%typemap(javaout) bool foo { return $jnicall; }
%typemap(in, numinputs=0) std::string& out (std::string temp) "$1=&temp;"
%typemap(argout) std::string& out {
$result = JCALL1(NewByteArray, jenv, $1->size());
JCALL4(SetByteArrayRegion, jenv, $result, 0, $1->size(), (const jbyte*)$1->c_str());
}
// Optional: return NULL if the function returned false
%typemap(out) bool foo {
if (!$1) {
return NULL;
}
}
%inline %{
struct Bar {
bool foo(std::string& out) {
std::string s;
s.push_back('H');
s.push_back('o');
s.push_back(0);
s.push_back('l');
s.push_back('a');
out = s;
return true;
}
};
%}
它声明C ++包装器为函数返回一个Java字节数组匹配 bool foo
。它还设置一个临时的 std :: string
来提供隐藏输入参数的 foo
的实际实现Java接口本身。
It states that the C++ wrapper with return a Java byte array for the functions that match bool foo
. It also sets up a temporary std::string
to give to the real implementation of foo
that hides the input parameter from the Java interface itself.
一旦调用完成,它就会创建并返回一个字节数组,前提是函数没有返回false。
Once the call has been made it creates and returns a byte array provided the function didn't return false.
我检查了它是否按预期工作:
I checked that it all worked as expected with:
public class run {
public static void main(String[] argv) {
String s = "ho\0la";
System.out.println(s.getBytes().length);
System.loadLibrary("test");
Bar b = new Bar();
byte[] bytes = b.foo();
s = new String(bytes);
System.out.println(s + " - " + s.length());
assert(s.charAt(2) == 0);
}
}
你应该知道演员阵容的含义返回类型为 c_str()
的 const jbyte *
- 它可能并不总是你想要的。
You should be aware of the implications of the cast to const jbyte*
from the return type of c_str()
- it may not always be what you wanted.
作为替代方案,如果输出字节数组的大小实际上是固定的或平凡可预测的,您可以将其作为输入开始预先分配。这可以工作,因为数组首先通过引用有效地传递给函数。
As an alternative if the size of the output byte array was actually fixed or trivially predictable you could pass that in pre-allocated as the input to begin with. This would work because arrays are effectively passed by reference into functions in the first place.
这篇关于Swig:将返回类型std :: string(二进制)转换为java byte []的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!