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

2023-11-25

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

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

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

该函数返回的整数是错误代码,以防失败。论据是

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

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

为绑定生成的 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 它需要知道什么。家里有打字机吗?


感谢托马斯在正确的方向上的推动。解决方案是创建一个自定义类型映射,使用 StringBuffer 来获取结果。我在中找到了代码examples/java/typemapSWIG 安装目录。我一定是在之前搜索的时候忽略了这一点。

我已附上下面的示例代码,我目前正在使用建议的替代方法。然而,使用 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);
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

随机推荐

  • Matplotlib图形facecolor(背景颜色)

    有人可以解释一下为什么下面的代码在设置图形的面部颜色时不起作用吗 import matplotlib pyplot as plt create figure instance fig1 plt figure 1 fig1 set fighe
  • Ansible 循环处理 URI 调用的 JSON 输出

    一段时间以来我一直在尝试让它发挥作用 但我无法做到这一点 我希望这是我所缺少的一些很小的东西 我正在尝试解析使用 with items 的任务的 JSON 输出 我知道最终组件的变量列表将包含在结果数组中 name Get list of
  • Swift:检查字符串是否有数组中的元素

    我想检查一个字符串是否至少包含数组中的一个元素 我试过这个 但我认为它太长了 想象一下 如果我想要 if 语句中的所有字母表 我希望有一个适当的方法来做到这一点 var str Hello playground let typeString
  • 无法将项目导入到android studio

    我正在尝试使用this library 我已经添加 compile net rdrei android dirchooser library 2 0 aar 到依赖项 我的顶级构建文件 Top level build file where
  • 创建一个零填充的二维数组,其位置由向量索引

    我正在尝试向量化以下 MATLAB 操作 给定一个带有索引的列向量 我想要一个带有 相同数量的行和固定数量的列 这 矩阵用零初始化并在位置中包含 1 由索引指定 这是我已经编写的脚本的示例 y 1 3 2 1 3 m size y 1 Fo
  • EditorFor() 和 html 属性

    Asp Net MVC 2 0 预览版提供了类似的帮助器 Html EditorFor c gt c propertyname 如果属性名称是字符串 上面的代码将呈现一个文本框 如果我想将 MaxLength 和 Size 属性传递到文本框
  • 如何获取真实运行的进程名称?

    在 NET core 控制台应用程序中 我想获取正在运行的进程名称 我使用ProcessName正如文档所说 但它总是返回dotnet作为进程名称 而不是正在运行的实际下划线 dll 虽然它是一个 dll 但这是一个控制台应用程序 而不是一
  • 空格导致 PowerShell 路径分割

    在包含空格的路径中调用 exe 时 我遇到了 powershell 问题 PS C Windows Services gt invoke expression C Windows Services MyService exe 术语 C Wi
  • 如何在 Scala/Lift 中惯用地处理 null 检查?

    即使 Box 和 Option monad 很流行 我们仍然必须到处检查空值 到目前为止我想出的最好的方法是使用 Box 方法 Box possiblyNull map toString openOr 有一个更好的方法吗 我尝试使用 Box
  • Eclipse 终止键盘快捷键

    How do I get eclipse to terminate I use the keyboard shortcut Ctrl F11 to run a program and I cannot enable the terminat
  • Expo 构建 EAS - 本地 - 未找到 SDK 位置

    当我使用来自博览会的新构建工具时EAS在本地构建我的 React Native 应用程序 eas build platform android local 我收到一个错误 未找到 SDK 位置 使用 ANDROID SDK ROOT 定义位
  • 给定一组点,如何找到彼此最远的两个点? [复制]

    这个问题在这里已经有答案了 可能的重复 最大线性尺寸二维点集 我可以计算每个点之间的距离并取最大的距离 但是当有大量 gt 1000 点时 这听起来不是一种非常有效的方法 注意 这是针对 iPhone 的 所以我没有太多的处理能力 为什么不
  • 如果没有堆内存,如何释放 std::vector

    我有一个这样的类成员变量 vector
  • 在 Microsoft Outlook 中使用 applescript 创建新的外发邮件

    我正在尝试使用 Microsoft Outlook 2011 for mac 创建新的外发邮件 使用AppleScript 以下示例适用于10 6 8 tell application Microsoft Outlook set newMe
  • 数据库大小计算?

    估计具有以下特征的数据库有多大的最准确方法是什么 MySQL 1 Table with three columns id gt 大整型 字段1 gt varchar 32 字段2 gt 字符 32 field2 上有一个索引 您可以假设 v
  • 在 bash 中创建 RS256 JWT

    我正在尝试仅使用 bash 和 openSSL 构建 RS256 JWT 令牌 我可以使用的开发工具有限 我设计了一个脚本 它从 txt 文件中获取标头和有效负载 去掉换行符等 base 64URL 对它们进行编码并用 将它们连接在一起 分
  • Mongoose .update() 不会触发验证检查

    我可以设置超出枚举数组的值 但我不知道为什么猫鼬不验证该值 我是否以错误的方式更新枚举 my code var OrderSchema new mongoose Schema status type String enum created
  • 如何在Python 3中将具有属性的对象转换为不带“_”的JSON?

    我想将 Python 对象转换为 JSON 格式 类的私有属性User使用属性定义 方法to Json 我已经发现here class User def init self self name None self gender None p
  • 使用 Java 以编程方式确定 2 个图像是否看起来相同 [关闭]

    Closed 这个问题需要多问focused 目前不接受答案 在JAVA中 我试图以编程方式判断两个图像在屏幕上显示时是否相等 又名相同的图像 即使它们具有不同的值 色彩空间 是否有一段代码在呈现 2 个图像时会返回布尔值 我的示例之一是将
  • 如何使 Swig 正确包装在 C 中修改为 Java Something-or-other 的 char* 缓冲区?

    我正在尝试包装一些遗留代码以便在 Java 中使用 我很高兴看到 Swig 能够处理头文件 并且它生成了一个几乎可以工作的出色包装器 现在我正在寻找让它真正发挥作用的深层魔力 在 C 中我有一个看起来像这样的函数 DLL IMPORT in