Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing byte[] from Java to C++

Tags:

java

swig

I'm trying to pass a byte[] param with binary data and a string param from Java to C++ code using SWIG.

Here are my .i and .cpp files:

my_module.i

%module mymodule
%inline %{
   extern void compress_buffer_to_file(unsigned char *buffer, char *ofname);
%}

my_module.cpp

void compress_buffer_to_file(unsigned char *buffer, char *ofname){
   .........
}

The generated method in the Java wrapper:

public static void compress_buffer_to_file(SWIGTYPE_p_unsigned_char buffer, String ofname) {
   my_moduleJNI.compress_buffer_to_file(SWIGTYPE_p_unsigned_char.getCPtr(buffer), ofname);
}

How can I define a .i file that will generate a Java wrapper that will let me pass byte[] instead of SWIGTYPE_p_unsigned_char to the compress_buffer_to_file method or alternatively? How do I associate an existing byte[] on the Java side with a SWIGTYPE_p_unsigned_char?

I've tried to use typemap with no success.

like image 771
Black0ut Avatar asked Nov 03 '15 16:11

Black0ut


1 Answers

You want SWIG to perform a conversion between Java and C++ types, namely

  1. Java byte[] to unsigned char * and
  2. String to char *.

The general tools for such conversions are SWIG typemaps. Conveniently, many are already provided by SWIG and simply need to be applied. Have a look at the Java typemap documentation.

The latter conversion (String to char *) is done automatically by SWIG (using predefined typemaps that match char * arguments).

Using predefined typemaps

A standard conversion very similar to what you want (byte[] to char *) is handled by the "char * BYTE" typemaps defined in the file various.i. To use it, all you need to do is add

%include various.i
%apply char *BYTE { char *buffer_variable_name };

at the top of the swig interface file, where buffer_variable_name is the name of the variable in the function argument (typemaps can be matched by name). For details, see the general typemap documentation and the Java typemap documentation.

However, this is not exactly what you want, since your function takes an unsigned char *. If you can use java.nio.Buffer instead of byte[] on the Java side (which needs to be allocated via allocateDirect), there is a different set of typemaps predefined in various.i that can be used via

%apply unsigned char *NIOBUFFER { unsigned char *buffer_variable_name };

Writing your "own" typemaps

In your case you want essentially the same as the provided "char * BYTE" typemaps, but for functions taking unsigned char *. So you can just copy these from various.i to a new file ubyte.i and tweak them slightly:

ubyte.i

%typemap(jni) unsigned char *UBYTE "jbyteArray"
%typemap(jtype) unsigned char *UBYTE "byte[]"
%typemap(jstype) unsigned char *UBYTE "byte[]"
%typemap(in) unsigned char *UBYTE {
  $1 = (unsigned char *) JCALL2(GetByteArrayElements, jenv, $input, 0); 
}

%typemap(argout) unsigned char *UBYTE {
  JCALL3(ReleaseByteArrayElements, jenv, $input, (jbyte *) $1, 0); 
}

%typemap(javain) unsigned char *UBYTE "$javainput"

/* Prevent default freearg typemap from being used */
%typemap(freearg) unsigned char *UBYTE "" 

Use these in the same way, by adding at the top of your swig interface file:

%include ubyte.i
%apply unsigned char *UBYTE { unsigned char *buffer_variable_name };

Using these predefined typemaps as a basic example, and reading the docs, you can then start writing your own custom typemaps if you need to.

Hope this helps.

like image 130
m7thon Avatar answered Nov 15 '22 18:11

m7thon