You're on the right lines with carrays.i, although normally I'd prefer to use %array_class
instead of %array_functions
when given a choice. The problem is that your array_functions/array_class gives you a SWIGTYPE_p_unsigned_char
(i.e. proxy for pointer to unsigned char
) whereas you need a void
pointer and there's no trivial way to convert between the two because of the strong typing in Java. We can work around that though.
To illustrate this answer I created a very simple header file that reproduces your problem:
typedef struct sp_session_config {
const void *application_key; ///< Your application key
} session_config;
so the problem is that we can't call setApplication_key()
with an array_class/array_function generated uint8_t
array because the types don't match.
There's quite a few possible solutions to that. One way might be to tell SWIG to ignore application_key
in sp_session_config
and instead pretend that it's a uint8_t* application_key
. To do that you need to supply a set/get function in C for the wrapper that does the work (trivial in this case) and use %ignore
to hide the "real" member, %extend
to add the "fake" member and %rename
to stop the %ignore
ignoring the fake one:
%module test
%{
#include "test.h"
#include <stdint.h>
// Internal helpers for our fake memeber
static void session_config_application_key_set(session_config *cfg, const uint8_t *arr) {
cfg->application_key = arr;
}
static const uint8_t *session_config_application_key_get(const session_config *cfg) {
return cfg->application_key;
}
%}
%include <carrays.i>
%include <stdint.i>
%array_class(uint8_t, uint8Array);
%ignore sp_session_config::application_key; // ignore the real one when we see it
%include "test.h"
%rename("%s") sp_session_config::application_key; // unignore for extend
%extend session_config {
uint8_t *application_key;
}
This is sufficient to allow us to write, in Java:
public class run {
public static void main(String[] argv) {
session_config cfg = new session_config();
uint8Array key = new uint8Array(4);
key.setitem(0, (short)100); key.setitem(1, (short)101);
key.setitem(2, (short)102); key.setitem(3, (short)103);
cfg.setApplication_key(key.cast());
}
}
Alternatively if you'd rather you can use the typemap system to expose the member as a uint8_t*
instead:
%module test
%{
#include "test.h"
%}
%include <carrays.i>
%include <stdint.i>
%array_class(uint8_t, uint8Array);
%typemap(jstype) const void *application_key "$typemap(jstype, const uint8_t*)"
%typemap(javain) const void *application_key "$typemap(jstype, const uint8_t*).getCPtr($javainput)"
%typemap(javaout) const void *application_key {
long cPtr = $jnicall;
return (cPtr == 0) ? null : new $typemap(jstype, const uint8_t*)(cPtr, $owner);
}
%include "test.h"
which matches only const void *application_key
and generates code in the interface to work with the wrapped uint8_t*
instead of the void*
.
Another possible approach would be to simply claim to SWIG that the member is a uint8_t*
, by providing a special definition of the struct
inside the interface file:
%module test
%{
#include "test.h"
%}
%include <carrays.i>
%include <stdint.i>
%array_class(uint8_t, uint8Array);
typedef struct sp_session_config {
const uint8_t *application_key;
} session_config;
// Ignore the one in the header file, use our special version instead
%ignore sp_session_config;
%include "test.h"
Doing it this way is simple, but trickier to maintain - every time sp_session_config
changes you'll have to make sure you update the interface file to match it otherwise you risk not exposing, or even incorrectly exposing the struct
.
A word of caution: be careful with the ownership in these examples - the array on the Java side retains ownership, so you need to make sure that:
- the C library won't try to free it (you'll see a double
free()
if it does)
- the lifetime of the array in Java exceeds the usage of it in the C library.
You could make the C library take ownership of the memory if you wanted, the easiest of these examples to do that with would be the one using typemaps. (You could modify the javain typemap to also take ownership).
Finally for yet another possible solution you could use a little bit of JNI or yet more other techniques as I've answered in the past to use a Java array or generate suitable code for this.