gpt4 book ai didi

java - 如何使 Swig 正确包装在 C 中修改为 Java Something-or-other 的 char* 缓冲区?

转载 作者:塔克拉玛干 更新时间:2023-11-03 04:11:06 25 4
gpt4 key购买 nike

我正在尝试包装一些遗留代码以便在 Java 中使用,我很高兴看到 Swig 能够处理头文件并且它生成了一个几乎可以工作的优秀包装器。现在我正在寻找能让它真正发挥作用的深层魔法。

在 C 中我有一个看起来像这样的函数

DLL_IMPORT int DustyVoodoo(char *buff, int len,  char *curse);

此函数返回的这个整数是错误代码,以防失败。参数是

  • buff 是一个字符缓冲区
  • len是缓冲区中数据的长度
  • curse 包含调用 DustyVoodoo 的结果的另一个字符缓冲区

所以,你可以看到这是怎么回事,结果实际上是通过第三个参数返回的。另外 len 令人困惑,因为它可能是两个缓冲区的长度,它们在调用代码中总是被分配为相同的大小但是考虑到 DustyVoodoo 我不认为他们需要相同。为了安全起见,两个缓冲区在实践中应该具有相同的大小,比如 512 个字符。

绑定(bind)生成的C代码如下:

SWIGEXPORT jint JNICALL Java_pemapiJNI_DustyVoodoo(JNIEnv *jenv, jclass jcls, jstring 

jarg1, jint jarg2, jstring jarg3) {
jint jresult = 0 ;
char *arg1 = (char *) 0 ;
int arg2 ;
char *arg3 = (char *) 0 ;
int result;

(void)jenv;
(void)jcls;
arg1 = 0;
if (jarg1) {
arg1 = (char *)(*jenv)->GetStringUTFChars(jenv, jarg1, 0);
if (!arg1) return 0;
}
arg2 = (int)jarg2;
arg3 = 0;
if (jarg3) {
arg3 = (char *)(*jenv)->GetStringUTFChars(jenv, jarg3, 0);
if (!arg3) return 0;
}
result = (int)PemnEncrypt(arg1,arg2,arg3);
jresult = (jint)result;
if (arg1) (*jenv)->ReleaseStringUTFChars(jenv, jarg1, (const char *)arg1);
if (arg3) (*jenv)->ReleaseStringUTFChars(jenv, jarg3, (const char *)arg3);
return jresult;
}

它的作用是正确的;然而,它忽略了一个事实,即 cursed 不仅仅是一个输入,它被函数改变并且应该作为输出返回。它也不知道 java 字符串实际上是缓冲区,应该由适当大小的数组支持。

我认为 Swig 可以在这里做正确的事情,我只是无法从文档中弄清楚如何告诉 Swig 它需要知道什么。房子里有 typemap masers 吗?

最佳答案

感谢 Thomas 在正确方向上的插入。解决方案是创建一个使用 StringBuffer 返回结果的自定义类型映射。我在 SWIG 安装的 examples/java/typemap 目录中找到了代码。我一定是在搜索之前忽略了这一点。

我附上了下面的示例代码,我目前正在使用建议的替代方法。但是,使用 BYTE 类型映射的第一种方法需要对我的 Java 代码进行一些更改,但从长远来看实际上可能更有意义。

感谢您的帮助,现在我看看是否可以接受我自己的答案...

/* File : example.i */
%module example
%{
/*
example of a function that returns a value in the char * argument
normally used like:

char buf[bigenough];
f1(buf);
*/

void f1(char *s) {
if(s != NULL) {
sprintf(s, "hello world");
}
}

void f2(char *s) {
f1(s);
}

void f3(char *s) {
f1(s);
}

%}

/* default behaviour is that of input arg, Java cannot return a value in a
* string argument, so any changes made by f1(char*) will not be seen in the Java
* string passed to the f1 function.
*/
void f1(char *s);

%include various.i

/* use the BYTE argout typemap to get around this. Changes in the string by
* f2 can be seen in Java. */
void f2(char *BYTE);



/* Alternative approach uses a StringBuffer typemap for argout */

/* Define the types to use in the generated JNI C code and Java code */
%typemap(jni) char *SBUF "jobject"
%typemap(jtype) char *SBUF "StringBuffer"
%typemap(jstype) char *SBUF "StringBuffer"

/* How to convert Java(JNI) type to requested C type */
%typemap(in) char *SBUF {

$1 = NULL;
if($input != NULL) {
/* Get the String from the StringBuffer */
jmethodID setLengthID;
jclass sbufClass = (*jenv)->GetObjectClass(jenv, $input);
jmethodID toStringID = (*jenv)->GetMethodID(jenv, sbufClass, "toString", "()Ljava/lang/String;");
jstring js = (jstring) (*jenv)->CallObjectMethod(jenv, $input, toStringID);

/* Convert the String to a C string */
const char *pCharStr = (*jenv)->GetStringUTFChars(jenv, js, 0);

/* Take a copy of the C string as the typemap is for a non const C string */
jmethodID capacityID = (*jenv)->GetMethodID(jenv, sbufClass, "capacity", "()I");
jint capacity = (*jenv)->CallIntMethod(jenv, $input, capacityID);
$1 = (char *) malloc(capacity+1);
strcpy($1, pCharStr);

/* Release the UTF string we obtained with GetStringUTFChars */
(*jenv)->ReleaseStringUTFChars(jenv, js, pCharStr);

/* Zero the original StringBuffer, so we can replace it with the result */
setLengthID = (*jenv)->GetMethodID(jenv, sbufClass, "setLength", "(I)V");
(*jenv)->CallVoidMethod(jenv, $input, setLengthID, (jint) 0);
}
}

/* How to convert the C type to the Java(JNI) type */
%typemap(argout) char *SBUF {

if($1 != NULL) {
/* Append the result to the empty StringBuffer */
jstring newString = (*jenv)->NewStringUTF(jenv, $1);
jclass sbufClass = (*jenv)->GetObjectClass(jenv, $input);
jmethodID appendStringID = (*jenv)->GetMethodID(jenv, sbufClass, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
(*jenv)->CallObjectMethod(jenv, $input, appendStringID, newString);

/* Clean up the string object, no longer needed */
free($1);
$1 = NULL;
}
}
/* Prevent the default freearg typemap from being used */
%typemap(freearg) char *SBUF ""

/* Convert the jstype to jtype typemap type */
%typemap(javain) char *SBUF "$javainput"

/* apply the new typemap to our function */
void f3(char *SBUF);

关于java - 如何使 Swig 正确包装在 C 中修改为 Java Something-or-other 的 char* 缓冲区?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2740068/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com