I am trying to wrap some legacy code for use in Java and I was quite happy to see that Swig was able to handle the header file and it generate a great wrapper that almost wo
Another simple and dumb workaround if you are as lazy as I am and if you have the liberty to change the prototype of C/C++ function slightly. Change the type of your parameter ( in your interface file) to unsigned char* instead of char* and then SWIG maps it to SWIGTYPE_p_unsigned_char :-) instead of String in Java
Perhaps this part of the SWIG documentation is helpful:
A common problem in some C programs is handling parameters passed as simple pointers or references. For example:
void add(int x, int y, int *result) { *result = x + y; }
[...]
The typemaps.i library file will help in these situations. For example:
%module example %include "typemaps.i" void add(int, int, int *OUTPUT);
There's also a section on wrapping arrays.
I'm sorry this isn't a ready-made, complete answer. SWIG is mind-bending at times.
Thanks to Thomas for the nudge in the correct direction. The solution to this was to create a custom typemap that uses a StringBuffer to get the result back. I found the code in the examples/java/typemap
directory of the SWIG install. I must have overlooked that before while I was searching.
I have attached the example code below, I am presently using the alternative approach suggested. However, the first approach of using the BYTE typemap wil require some changes in my Java code but might actually make more sense in the long run.
Thanks for the help, and now I get to see if I can accept my own answer...
/* File : example.i */
%module example
%{
/*
example of a function that returns a value in the char * argument
normally used like:
char buf[bigenough];
f1(buf);
*/
void f1(char *s) {
if(s != NULL) {
sprintf(s, "hello world");
}
}
void f2(char *s) {
f1(s);
}
void f3(char *s) {
f1(s);
}
%}
/* default behaviour is that of input arg, Java cannot return a value in a
* string argument, so any changes made by f1(char*) will not be seen in the Java
* string passed to the f1 function.
*/
void f1(char *s);
%include various.i
/* use the BYTE argout typemap to get around this. Changes in the string by
* f2 can be seen in Java. */
void f2(char *BYTE);
/* Alternative approach uses a StringBuffer typemap for argout */
/* Define the types to use in the generated JNI C code and Java code */
%typemap(jni) char *SBUF "jobject"
%typemap(jtype) char *SBUF "StringBuffer"
%typemap(jstype) char *SBUF "StringBuffer"
/* How to convert Java(JNI) type to requested C type */
%typemap(in) char *SBUF {
$1 = NULL;
if($input != NULL) {
/* Get the String from the StringBuffer */
jmethodID setLengthID;
jclass sbufClass = (*jenv)->GetObjectClass(jenv, $input);
jmethodID toStringID = (*jenv)->GetMethodID(jenv, sbufClass, "toString", "()Ljava/lang/String;");
jstring js = (jstring) (*jenv)->CallObjectMethod(jenv, $input, toStringID);
/* Convert the String to a C string */
const char *pCharStr = (*jenv)->GetStringUTFChars(jenv, js, 0);
/* Take a copy of the C string as the typemap is for a non const C string */
jmethodID capacityID = (*jenv)->GetMethodID(jenv, sbufClass, "capacity", "()I");
jint capacity = (*jenv)->CallIntMethod(jenv, $input, capacityID);
$1 = (char *) malloc(capacity+1);
strcpy($1, pCharStr);
/* Release the UTF string we obtained with GetStringUTFChars */
(*jenv)->ReleaseStringUTFChars(jenv, js, pCharStr);
/* Zero the original StringBuffer, so we can replace it with the result */
setLengthID = (*jenv)->GetMethodID(jenv, sbufClass, "setLength", "(I)V");
(*jenv)->CallVoidMethod(jenv, $input, setLengthID, (jint) 0);
}
}
/* How to convert the C type to the Java(JNI) type */
%typemap(argout) char *SBUF {
if($1 != NULL) {
/* Append the result to the empty StringBuffer */
jstring newString = (*jenv)->NewStringUTF(jenv, $1);
jclass sbufClass = (*jenv)->GetObjectClass(jenv, $input);
jmethodID appendStringID = (*jenv)->GetMethodID(jenv, sbufClass, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
(*jenv)->CallObjectMethod(jenv, $input, appendStringID, newString);
/* Clean up the string object, no longer needed */
free($1);
$1 = NULL;
}
}
/* Prevent the default freearg typemap from being used */
%typemap(freearg) char *SBUF ""
/* Convert the jstype to jtype typemap type */
%typemap(javain) char *SBUF "$javainput"
/* apply the new typemap to our function */
void f3(char *SBUF);