Как я могу заставить Большой глоток правильно перенести символ* буфер, который изменяется в C как То или другое Java?

Я пытаюсь перенести некоторый унаследованный код для использования в 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 мазеры в доме?

7
задан Ukko 29 April 2010 в 20:36
поделиться

2 ответа

Спасибо Томасу за толчок в правильном направлении. Решением было создать настраиваемую карту типов, которая использует 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);
7
ответ дан 6 December 2019 в 19:34
поделиться

Возможно эта часть документации SWIG будет полезна:

Распространенной проблемой в некоторых программах на C является обработка параметров, передаваемых как простые указатели или ссылки. Например:

 void add (int x, int y, int * result) {
 * result = x + y; 
} 
  
{ {1}}

[...]

В этих ситуациях поможет файл библиотеки typemaps.i. Например:

% module example 
% include "typemaps.i" 
 
void add (int, int, int * OUTPUT); 
 

Также есть раздел об упаковке массивов .

Мне жаль, что это не готовый полный ответ. SWIG временами умопомрачивает.

6
ответ дан 6 December 2019 в 19:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: