I am trying to use Swig to generate wrappers for some in-house C-code so I can reuse it for a new Android java project and am having problems. I am new to both Java and Swig so please be gentle with me in terms of the technical content of any replies.
I am trying to wrap a C-structure called S_MESSAGE_STRUCT which contains pointers in such a way that its elements can be accessed (set up, written, read etc) from java and also by legacy C code. My C header file defining the struct is as follows, the code is exemplary and simplified from my real code (which has the same problems) :
#ifndef MESSAGE_H_
#define MESSAGE_H_
#include <stdbool.h>
typedef struct
{
int* i1;
char* c1;
int len;
} *P_S_MESSAGE_STRUCT, S_MESSAGE_STRUCT;
bool t_func(P_S_MESSAGE_STRUCT p_s_mystruct);
#endif /* ndef MESSAGE_H_ */
My C file contains a single function which tests the int* i1 element of the S_MESSAGE_STRUCT and then writes to the c1 and i1 elements as follows :
#include "message.h"
bool t_func(P_S_MESSAGE_STRUCT p_s_mystruct)
{
if (*p_s_mystruct->i1 == 1)
{
strcpy(p_s_mystruct->c1, "Hello from swig");
p_s_mystruct->c1[p_s_mystruct->len-1] = '\0';
*p_s_mystruct->i1 = strlen(p_s_mystruct->c1);
}
return true;
}
I am using a .i file as follows :
/* File : Message.i */
%module Message
%{
/* Includes the header in the wrapper code */
#include "../../../common/message/message.h"
%}
// Enable the JNI class to load the required native library.
%pragma(java) jniclasscode=%{
static {
try {
java.lang.System.loadLibrary("Message");
} catch (UnsatisfiedLinkError e) {
java.lang.System.err.println("native code library failed to load.\n" + e);
java.lang.System.exit(1);
}
}
%}
%include <typemaps.i>
%apply signed char * INOUT {char*};
typedef struct
{
int* i1;
char* c1;
int len;
} *P_S_MESSAGE_STRUCT, S_MESSAGE_STRUCT;
%include cpointer.i
bool t_func(P_S_MESSAGE_STRUCT p_s_mystruct);
%pointer_functions(int, intp);
My java source function is as follows (edited from a default Android Activity) :
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/* typedef struct
{
int* i1;
char* c1;
int len;
}*P_MYSTRUCT, MYSTRUCT;
*/
S_MESSAGE_STRUCT p_my_struct = new S_MESSAGE_STRUCT();
int i1 = 1;
SWIGTYPE_p_int i1p = Message.new_intp();
Message.intp_assign(i1p, i1);
int len = 128;
byte[] c1 = new byte[len];
p_my_struct.setI1(i1p);
p_my_struct.setC1(c1);
p_my_struct.setLen(len);
Message.t_func(p_my_struct);
Integer i1_ret = Message.intp_value(i1p);
byte[] ret_c1 = p_my_struct.getC1();
String display = new String();
// !! display = Arrays.toString(ret_c1); // <<<< Gives Exception !!
display += i1_ret;
final EditText eText = (EditText) findViewById(R.id.editText1);
eText.setText(display);
}
Everything compiles and builds OK and there are no errors from the swig invocation of :
swig -java -package com.mobbu.Message -outdir ../../src/com/mobbu/Message/ -verbose Message.i
but I know that I am doing something wrong because I keep getting flakey problems after I call the t_func() function from java. The problems are various and include the program hanging after the call to t_func() completes but sometimes the program runs and displays an output OK. When output is displayed the contribution due to c1 is null (it just gives output "15" with no signs of "Hello from swig".
I have determined that the program flakiness stems from the writes to the pointer elements i1 and c1 in the P_MYSTRUCT struct, because there are no problems either without those elements or without the writes (but leaving the c1,i1 elements in the struct).
I would be very grateful for help on how to achieve my goal of being able to use pointer elements of C structs and for any ideas of what I am doing wrong in my Message.i file ? I am using SWIG Version 3.0.2. Thanks,
Mike
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!Edit:
I discovered that if I change the following line in message.i
%apply signed char * INOUT {char*};
to
%apply byte * INOUT {char*};
my Swig invocation gives the following error :
Warning 453: Can't apply (byte *INOUT). No typemaps are defined.
However the generated code compiles and runs OK with the proviso that I need to change my java application code to use a String instead of a byte[] for its version of c1.
My new java code is :
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/* typedef struct
{
int* i1;
char* c1;
int len;
}*P_MYSTRUCT, MYSTRUCT;*/
S_MESSAGE_STRUCT p_my_struct = new S_MESSAGE_STRUCT();
int i1 = 1;
SWIGTYPE_p_int i1p = Message.new_intp();
Message.intp_assign(i1p, i1);
int len = 128;
byte[] c1 = new byte[len];
String s1 = new String(c1);
p_my_struct.setI1(i1p);
p_my_struct.setC1(s1);
p_my_struct.setLen(len);
Message.t_func(p_my_struct);
SWIGTYPE_p_int pi1_ret = p_my_struct.getI1();
Integer i1_ret = Message.intp_value(pi1_ret);
String display = p_my_struct.getC1();
display += i1_ret;
final EditText eText = (EditText) findViewById(R.id.editText1);
eText.setText(display);
}
Does this shed any light on what I may be doing wrong ?
Any ideas gratefully received,
Mike