1

これは、 C++ から Java への ByteBuffer リターンを使用する方法という質問のフォローアップです。これまでのところ、Flexo の絶え間ないサポートに感謝します。まだタイプマップに慣れていないだけだと思います... :-(

次のように 4 つの引数を持つ C 関数があります。3 番目と 4 番目の引数は参照によって渡されます。

extern "C" int foo(const char* passByValText, const int passbyValLen, 
             unsigned char* retTextByRef, int *retTextLen) 

Calling Java Wrapper 関数は、次のようにする必要があります。

int foo(String passByValText, int passbyValLen, byte[] retBuf, SWIGTYPE_p_int retTextLen);

あるいは、それは可能性があります

int foo(String passByValText, int passbyValLen, ByteBuffer retBuf, SWIGTYPE_p_int retTextLen);

私が書いたタイプマップの謝罪を共有することができます - しかし基本的にそれは問題をさらに混乱させるかもしれません..だから私はこれを白紙の状態に保ちます..

以下はc側のサンプルコードです

extern "C" int foo (const char* passByValText, const int passbyValLen, char *retTextByRef, int *retTextLen){
    // binary value stuffed in the retTextByRef. In real program I compute this
    unsigned char someText[10]={0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x00};    
    memcpy(cipherText,someText,9);
    // I set the length of the value I stuffed into the buffer in c program
    *cipherLen=9;
return 0;

}

そして、この c 関数を呼び出す Java プログラム

class Caller{
    public static void main(String[] args) {

    //Define the parameter to pass by reference!!
    SWIGTYPE_p_int retTextLen=MYMODULE.new_intp();

    //Create a Java Wrapper Instance 
    JavaWrapClass myWrap=new JavaWrapClass();

    StringBuffer sBuf = new StringBuffer(50);
    int retTextLenVal=0;
    myWrap.foo("PASSED-STRING-BY-VALUE", 24, sBuf, retTextLen);
    retTextLenVal= MYMODULE.intp_value(retTextLen);
    System.out.println("JAVA :: got length "+ retTextLenVal);
    System.out.println("JAVA :: got BUFFER "+ sBuf);
    }
}

ありがとうございます!

4

1 に答える 1

1

次のヘッダーを使用してテストしました。

static int foo(const char *passByValText, const int passByValLen,
               unsigned char *retTextByRef, int *retTextLen) {
  *retTextLen = passByValLen;
  if (retTextByRef) {
    memcpy(retTextByRef, passByValText, passByValLen);
  }
  return NULL == retTextByRef;
}

次に、この関数を適切にラップできる最も単純な (たとえば、カスタム タイプマップが最も少ない) SWIG インターフェイスをまとめました。

%module test

%{
#include "test.h"
%}

%apply (char *STRING, size_t LENGTH) { (const char *passByValText, const int passByValLen) };
// Use String instead of byte[] for input as requested in Q:
%typemap(jstype) (const char *passByValText, const int passByValLen) "String"
%typemap(javain) (const char *passByValText, const int passByValLen) "$javainput.getBytes()"

%include <arrays_java.i>

// Force unsigned char array to be byte[] in Java:
%apply signed char[]  { unsigned char *retTextByRef };

%include <typemaps.i>

// Use the OUTPUT typemap - it passes an array with only one element
// could also use cpointers.i if you prefer
%apply int *OUTPUT { int *retTextLen };

%include "test.h"

これは、関数を 3 つの入力 (出力配列用のaと出力用の a)fooを取る関数として公開することになります。Stringbyte[]int[]int

これにより、次のように書くことができました。

public class run {
  public static void main(String[] argv) {
    System.loadLibrary("test");
    byte arr[] = new byte[100];
    int sz[] = {100};
    test.foo("Hello world", arr, sz);
    System.out.println(new String(arr, 0 , sz[0]));    
  }
}

テストしたときに期待どおりに機能しました。arrays_java.i の typemaps はnull配列を拒否するため、if私が書いたサンプルの を使用して出力サイズを照会することはできません。

StringBuffera の代わりに aを使用する場合byte[]、最も簡単な解決策は%pragma、Java でオーバーロードを生成するために使用することです。

%pragma(java) modulecode = %{
  public static int foo(String in, StringBuffer out) {
    int sz[] = {out.capacity()};
    byte ret[] = new byte[out.capacity()];
    final int v = test.foo(in, ret, sz);
    // Or whatever your preferred semantics are: 
    out.replace(0, sz[0], new String(ret, 0, sz[0]));
    return v;
  }
%}
于 2012-07-26T11:06:22.643 に答える