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.
I think you don't need to implement a mechanism of your own. swig provides a module named 'cdata.i'. You should include this in the interface definition file.
Once you include this, it gives two functions cdata() and memmove(). Given a void * and the length of the binary data, cdata() converts it into a string type of the target language. memmove() is the reverse. given a string type, it will copy the contents of the string(including embedded null bytes) into the C void* type.
Handling binary data becomes much simple with this module. I hope this is what you need.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With