1

I want to pass a segment of info (e.g. 1024 bytes of memory) between Java and C++ using SWIG. The structure defined in C++ is as follows:

struct Buffer
{
    unsigned char *addr;
    size_t        size;
}

How should I write the SWIG interface file for that purpose?

1
  • Yes. Just realized it. Thank you Melebius. :) Commented May 15, 2018 at 12:46

1 Answer 1

2

It's not entirely clear what you want to achieve exactly.

If you want to map your Buffer to a Java byte[], you can do it with a custom typemap:

%typemap(jni) Buffer "jbyteArray"
%typemap(jtype) Buffer "byte[]"
%typemap(jstype) Buffer "byte[]"
%typemap(in) Buffer {
    $1.addr = (unsigned char *) JCALL2(GetByteArrayElements, jenv, $input, 0);
    $1.size = JCALL1(GetArrayLength, jenv, $input);
}
%typemap(argout) Buffer {
    JCALL3(ReleaseByteArrayElements, jenv, $input, (jbyte *) $1.addr, 0);
}
%typemap(out) Buffer {
    $result = JCALL1(NewByteArray, jenv, $1.size);
    JCALL4(SetByteArrayRegion, jenv, $result, 0, $1.size, (jbyte *) $1.addr);
    delete[] $1.addr;
}
%typemap(javain) Buffer "$javainput"
%typemap(javaout) Buffer { return $jnicall; }

Then C++ code like

  Buffer getData();
  void sendData(Buffer arg);

Will be mapped to Java:

  public static byte[] getData() { ... }
  public static void sendData(byte[] arg) { ... }

The difficulty with passing data to Java is to get it into the JVM heap and/or to manage the lifetime of the data. It's easy to achieve with some copying, but a truly 0-copy solution will often require a change in the C++ interface.

Complete example:

example.h

#include <stddef.h>
struct Buffer
{
    unsigned char *addr;
    size_t        size;
};
Buffer getData();
void sendData(Buffer);

example.cxx

#include "example.h"

Buffer getData() {
    Buffer rc { new unsigned char[64], 64 };
    for (int i = 0; i < rc.size; ++i)
        rc.addr[i] = 0x40 + i;
    return rc;
}
void sendData(Buffer buf) {
    // use buf.addr
}

example.i

%module example
%{ 
#include "example.h"
%}
%typemap(jni) Buffer "jbyteArray"
%typemap(jtype) Buffer "byte[]"
%typemap(jstype) Buffer "byte[]"
%typemap(in) Buffer {
    $1.addr = (unsigned char *) JCALL2(GetByteArrayElements, jenv, $input, 0);
    $1.size = JCALL1(GetArrayLength, jenv, $input);
}
%typemap(argout) Buffer {
    JCALL3(ReleaseByteArrayElements, jenv, $input, (jbyte *) $1.addr, 0);
}
%typemap(out) Buffer {
    $result = JCALL1(NewByteArray, jenv, $1.size);
    JCALL4(SetByteArrayRegion, jenv, $result, 0, $1.size, (jbyte *) $1.addr);
    delete[] $1.addr;
}
%typemap(javain) Buffer "$javainput"
%typemap(javaout) Buffer { return $jnicall; }
%ignore Buffer;
%include "example.h"

test.java

class test {
    public static void main(String[] args) throws Exception {
       System.loadLibrary("_example");
       byte[] data = example.getData();
       System.out.println(new String(data));
    }
}

Output:

@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~⌂
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.