Я пытаюсь перенести некоторый унаследованный код для использования в Java, и я был довольно рад видеть, что Большой глоток смог обработать заголовочный файл, и это генерирует большую обертку, которая почти работает. Теперь я ищу глубокое волшебство, которое заставит его действительно работать.
В C у меня есть функция, которая похожа на это
DLL_IMPORT int DustyVoodoo(char *buff, int len, char *curse);
Это целое число, возвращенное этой функцией, является кодом ошибки в случае, если это перестало работать. Аргументы
buff
символьный буфер len
длина данных в буфереcurse
другой символьный буфер, который содержит результат вызова DustyVoodooТак, Вы видите, куда это идет, результат на самом деле возвращается через третий аргумент. Также len
сбивает с толку, так как это может быть длина обоих буферов, они всегда выделяются как являющийся тем же размером в коде вызова, но даются что DustyVoodoo
делает я не думаю, что они должны быть тем же. Для сейфа, оба буфера должны быть тем же размером на практике, сказать 512 символов.
Код C, сгенерированный для привязки, следующие:
SWIGEXPORT jint JNICALL Java_pemapiJNI_DustyVoodoo(JNIEnv *jenv, jclass jcls, jstring
jarg1, jint jarg2, jstring jarg3) {
jint jresult = 0 ;
char *arg1 = (char *) 0 ;
int arg2 ;
char *arg3 = (char *) 0 ;
int result;
(void)jenv;
(void)jcls;
arg1 = 0;
if (jarg1) {
arg1 = (char *)(*jenv)->GetStringUTFChars(jenv, jarg1, 0);
if (!arg1) return 0;
}
arg2 = (int)jarg2;
arg3 = 0;
if (jarg3) {
arg3 = (char *)(*jenv)->GetStringUTFChars(jenv, jarg3, 0);
if (!arg3) return 0;
}
result = (int)PemnEncrypt(arg1,arg2,arg3);
jresult = (jint)result;
if (arg1) (*jenv)->ReleaseStringUTFChars(jenv, jarg1, (const char *)arg1);
if (arg3) (*jenv)->ReleaseStringUTFChars(jenv, jarg3, (const char *)arg3);
return jresult;
}
Это корректно для того, что это делает; однако, это пропускает факт это cursed
не просто вход, он изменен функцией и должен быть возвращен как вывод. Это также не знает, что Строки Java являются действительно буферами и должны быть поддержаны соответственно размерным массивом.
Я думаю, что Большой глоток может сделать правильную вещь здесь, я просто не могу фигурировать из документации, как сказать Большой глоток, что это должно знать. Какие-либо typemap мазеры в доме?
Спасибо Томасу за толчок в правильном направлении. Решением было создать настраиваемую карту типов, которая использует StringBuffer для возврата результата. Я нашел код в каталоге examples / java / typemap
установки SWIG. Я, должно быть, не заметил этого раньше, пока искал.
Я приложил пример кода ниже, в настоящее время я использую предложенный альтернативный подход. Однако первый подход с использованием карты типов BYTE потребует некоторых изменений в моем Java-коде, но в конечном итоге может иметь больше смысла.
Спасибо за помощь, и теперь я проверю, могу ли я принять свой ответ ...
/* 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);
Возможно эта часть документации SWIG будет полезна:
Распространенной проблемой в некоторых программах на C является обработка параметров, передаваемых как простые указатели или ссылки. Например:
{ {1}}void add (int x, int y, int * result) { * result = x + y; }
[...]
В этих ситуациях поможет файл библиотеки typemaps.i. Например:
% module example % include "typemaps.i" void add (int, int, int * OUTPUT);
Также есть раздел об упаковке массивов .
Мне жаль, что это не готовый полный ответ. SWIG временами умопомрачивает.