包装无符号二进制数据的 SWIG 技术 [英] SWIG Technique to Wrap Unsigned Binary Data

查看:36
本文介绍了包装无符号二进制数据的 SWIG 技术的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 C 函数,它返回一个表示二进制数据的 unsigned char*.我在文档中注意到 SWIG 有一个很好的类型映射来处理二进制数据作为 C 函数的输入,但是当 C 函数返回二进制数据及其无符号数据时呢?有什么想法吗?

swig.i:

%apply (char *STRING, size_t LENGTH) { (const char data[], size_t len) }%排队 %{void binaryChar1(const char data[], size_t len) {printf("len: %d 数据:", len);for (size_t i=0; i

java:

byte[] data = "hi\0jk".getBytes();示例.binaryChar1(数据);

C 示例:

 enw_resultrow_t *result_row = getResultRow();无符号字符 *blob;而 ((blob = getBinaryFromRow(result_row, &length))) {字符 fname[32];文件 *fp;我++;snprintf (fname, sizeof(fname), "FileXYZ", i);printf ("%d 中的 Blob:%s 保存在 %s 中有 %d 个字节\n", i,aSender?inet_ntoa(aSender->sin_addr):"???", fname, length);如果((fp = fopen(fname,w"))){l = fwrite (blob, sizeof (unsigned char), length, fp);printf("成功将 %d 个字节写入文件\n", l);fclose (fp);} 别的 {printf("写入文件出错");}}

解决方案

我已经创建了一个测试用例来反映您正在尝试做的事情(我认为):

#include 枚举事物{一=1,二=2,三=3};静态签名 char *get_data(enum thing t, size_t *len) {*len = (size_t)t;签名字符 *ret = malloc(sizeof(signed char) * (*len));for (size_t i = 0; i < *len; ++i) {ret[i] = i;}返回 ret;}

为了包装 get_data() 我使用了以下接口:

%module 测试%{#include "test.h"%}%typemap(jni) 签名字符 *get_data "jbyteArray"%typemap(jtype) 有符号字符 *get_data "byte[]"%typemap(jstype) 有符号字符 *get_data "byte[]"%typemap(javaout) 符号字符 *get_data {返回 $jncall;}%typemap(in,numinputs=0,noblock=1) size_t *len {size_t 长度=0;$1 = &length;}%typemap(out) 有符号字符 *get_data {$result = JCALL1(NewByteArray, jenv, length);JCALL4(SetByteArrayRegion, jenv, $result, 0, length, $1);}%include "test.h"

基本上,它的作用是将 get_data 函数的返回类型设置为从 JNI 代码一直到 SWIG 代理的 Java 数组.完成后,它会设置一个名为 length 的临时 size_t,用于调用真正的 C 函数并存储结果.(在我看到 另一个问题的答案之前,我没有看到 noblock,它告诉 SWIG不要使 typemap 参数独立,因此意味着给定函数只能有一个 size_t *len 参数,如果您好奇,请查看它对生成的包装器代码的作用).

一旦设置完毕,剩下的就是使用 JNI 调用分配一个数组并将一些值复制到其中.

我对此进行了测试:

公共类运行{公共静态无效主(字符串 [] argv){System.loadLibrary("测试");byte[] test1 = test.get_data(thing.ONE);System.out.println(test1.length);System.out.println(test1 + ": " + test1[0]);byte[] test2 = test.get_data(thing.TWO);System.out.println(test2.length);System.out.println(test2 + ": " + test2[0] + ", " + test2[1]);byte[] test3 = test.get_data(thing.THREE);System.out.println(test3.length);System.out.println(test3 + ": " + test3[0] + ", " + test3[1] + ", " + test3[2]);}}

然后给出:

<前>1[B@525483cd:02[B@2a9931f5: 0, 13[B@2f9ee1ac: 0, 1, 2

我把我的变成了一个signed char,这有点作弊.如果你想让它无符号,你要么需要使用强制转换(最好注意符号丢失)或 short/int 并进行适当的转换.

注意真实代码中的内存所有权.

I have a C function that returns a unsigned char* that represents binary data. I noticed in the documentation that SWIG has a nice typemap to handle binary data as input to a C function, but what about when a C function returns binary data and its unsigned? Any ideas?

swig.i:

%apply (char *STRING, size_t LENGTH) { (const char data[], size_t len) }
%inline %{
void binaryChar1(const char data[], size_t len) {
  printf("len: %d data: ", len);
  for (size_t i=0; i<len; ++i)
    printf("%x ", data[i]);
  printf("\n");
}
%}

java:

byte[] data = "hi\0jk".getBytes();
example.binaryChar1(data);

C Example:

 enw_resultrow_t *result_row = getResultRow();
 unsigned char *blob;
 while ((blob = getBinaryFromRow(result_row, &length))) {
            char fname[32];
            FILE *fp;
            i++;
            snprintf (fname, sizeof(fname), "FileXYZ", i);
            printf ("Blob from %d:%s is saved in %s has %d bytes\n", i, 
                    aSender?inet_ntoa(aSender->sin_addr):"???", fname, length);
            if ((fp = fopen (fname, "w"))) {
                l = fwrite (blob, sizeof (unsigned char), length, fp);
                printf("Successfully wrote %d bytes to file\n", l);
                fclose (fp);
            } else {
                printf("Error writing file");
            }
        }

解决方案

I've created a test case that mirrors what you're trying to do (I think):

#include <stdlib.h>

enum thing {
  ONE=1,
  TWO=2, 
  THREE=3
};

static signed char *get_data(enum thing t, size_t *len) {
  *len = (size_t)t;
  signed char *ret = malloc(sizeof(signed char) * (*len));
  for (size_t i = 0; i < *len; ++i) {
    ret[i] = i;
  }
  return ret;
}

To wrap get_data() I used the following interface:

%module test

%{
#include "test.h"
%}

%typemap(jni) signed char *get_data "jbyteArray"
%typemap(jtype) signed char *get_data "byte[]"
%typemap(jstype) signed char *get_data "byte[]"
%typemap(javaout) signed char *get_data {
  return $jnicall;
}

%typemap(in,numinputs=0,noblock=1) size_t *len { 
  size_t length=0;
  $1 = &length;
}

%typemap(out) signed char *get_data {
  $result = JCALL1(NewByteArray, jenv, length);
  JCALL4(SetByteArrayRegion, jenv, $result, 0, length, $1);
}

%include "test.h"

Basically what this does is set the return type from the get_data function to be a Java array right from the JNI code all the way through the SWIG proxy. Once that's done it sets up a temporary size_t called length which will be used to make the call to the real C function and store the result. (I'd not seen noblock before I saw this answer to another question, it tells SWIG not to make the typemap argument independent and as such means there can only ever be one size_t *len parameter to a given function, take a look at what it does to the generated wrapper code if you're curious).

Once that's set then all that remains is to allocate an array using a JNI call and copy some values into it.

I tested this with:

public class run {
  public static void main(String[] argv) {
    System.loadLibrary("test");
    byte[] test1 = test.get_data(thing.ONE);
    System.out.println(test1.length);
    System.out.println(test1 + ": " + test1[0]);

    byte[] test2 = test.get_data(thing.TWO);
    System.out.println(test2.length);
    System.out.println(test2 + ": " + test2[0] + ", " + test2[1]);

    byte[] test3 = test.get_data(thing.THREE);
    System.out.println(test3.length);
    System.out.println(test3 + ": " + test3[0] + ", " + test3[1] + ", " + test3[2]);

  }
}

Which then gave:

1
[B@525483cd: 0
2
[B@2a9931f5: 0, 1
3
[B@2f9ee1ac: 0, 1, 2

I cheated slightly by making mine be a signed char. If you want to make it unsigned you either need to use a cast (beware the loss of sign at best) or short/int with an appropriate conversion.

Be careful with memory ownership in your real code.

这篇关于包装无符号二进制数据的 SWIG 技术的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆