The right way to interact with arrays using SWIG

I got a little lost with typemaps in swig and how to use arrays. I prepared a working example that uses arrays between java and c with swig, but I don't know if this is the right thing to do.

Basically, I want to transfer an array of bytes byte[]from java to c as aign char * `+ its size, change it in c and see the changes in java and create an array in c and use it in Java.

I will consider these issues: How to transfer an array (long array in java) from Java to C ++ using Swig , Pass the array to the wrapped function as a pointer + size or range , How to make Swig correctly wrap the char * buffer that has been changed to C how is java something or the other?

And actually used the solutions as a guide to create an example.

This is my code in arrays.h file:

#include <iostream>

bool createArray(signed char ** arrCA, int * lCA){
    *lCA = 10;
    *arrCA = (signed char*) calloc(*lCA, sizeof(signed char));

    for(int i = 0; i < *lCA; i++){
        (*arrCA)[i] = i;
    }

    return *arrCA != NULL;
}

bool readArray(const signed char arrRA[], const int lRA){
    for(int i = 0; i < lRA; i++){
        std::cout << ((unsigned int) arrRA[i]) << " ";
    }
    std::cout << std::endl;
    return true;
}

bool modifyArrayValues(signed char arrMA[], const int lMA){
    for(int i = 0; i < lMA; i++){
        arrMA[i] = arrMA[i] * 2;
    }
    return true;
}


bool modifyArrayLength(signed char arrMALIn[], int lMALIn, signed char ** arrMALOut, int * lMALOut){

    *lMALOut = 5;
    *arrMALOut = (signed char*) calloc(*lMALOut, sizeof(signed char));

    for(int i = 0; i < *lMALOut; i++){
        (*arrMALOut)[i] = arrMALIn[i];
    }
    return true;
}

This is the .i file for swig (arrays.i):

%module arrays

%{
    #include "arrays.h"
%}

%typemap(jtype) bool createArray "byte[]"
%typemap(jstype) bool createArray "byte[]"
%typemap(jni) bool createArray "jbyteArray"
%typemap(javaout) bool createArray { return $jnicall; }
%typemap(in, numinputs=0) signed char ** arrCA (signed char * temp) "$1=&temp;"
%typemap(in, numinputs=0) int * lCA (int l) "$1=&l;"
%typemap(argout) (signed char ** arrCA, int * lCA) {
    $result = JCALL1(NewByteArray, jenv, *$2);
    JCALL4(SetByteArrayRegion, jenv, $result, 0, *$2, (const jbyte*) *$1);
}
%typemap(out) bool createArray {
    if (!$1) {
        return NULL;
    }
}


%typemap(jtype) (const signed char arrRA[], const int lRA) "byte[]"
%typemap(jstype) (const signed char arrRA[], const int lRA) "byte[]"
%typemap(jni) (const signed char arrRA[], const int lRA) "jbyteArray"
%typemap(javain) (const signed char arrRA[], const int lRA) "$javainput"

%typemap(in,numinputs=1) (const signed char arrRA[], const int lRA) {
  $1 = JCALL2(GetByteArrayElements, jenv, $input, NULL);
  $2 = JCALL1(GetArrayLength, jenv, $input);
}

%typemap(freearg) (const signed char arrRA[], const int lRA) {
  // Or use  0 instead of ABORT to keep changes if it was a copy
  JCALL3(ReleaseByteArrayElements, jenv, $input, $1, JNI_ABORT); 
}


%typemap(jtype) (signed char arrMA[], const int lMA) "byte[]"
%typemap(jstype) (signed char arrMA[], const int lMA) "byte[]"
%typemap(jni) (signed char arrMA[], const int lMA) "jbyteArray"
%typemap(javain) (signed char arrMA[], const int lMA) "$javainput"

%typemap(in, numinputs=1) (signed char arrMA[], const int lMA) {
    $1 = JCALL2(GetByteArrayElements, jenv, $input, NULL);
    $2 = JCALL1(GetArrayLength, jenv, $input);
}

%typemap(freearg) (signed char arrMA[], const int lMA) {
  JCALL3(ReleaseByteArrayElements, jenv, $input, $1, 0); 
} 

%typemap(jtype) (signed char arrMALIn[], int lMALIn) "byte[]"
%typemap(jstype) (signed char arrMALIn[], int lMALIn) "byte[]"
%typemap(jni) (signed char arrMALIn[], int lMALIn) "jbyteArray"
%typemap(javain) (signed char arrMALIn[], int lMALIn) "$javainput"

%typemap(in, numinputs=1) (signed char arrMALIn[], int lMALIn) {
    $1 = JCALL2(GetByteArrayElements, jenv, $input, NULL);
    $2 = JCALL1(GetArrayLength, jenv, $input);
}

%typemap(freearg) (signed char arrMALIn[], int lMALIn) {
    JCALL3(ReleaseByteArrayElements, jenv, $input, $1, JNI_ABORT); 
}

%typemap(jtype) bool modifyArrayLength "byte[]"
%typemap(jstype) bool modifyArrayLength "byte[]"
%typemap(jni) bool modifyArrayLength "jbyteArray"
%typemap(javaout) bool modifyArrayLength { return $jnicall; }
%typemap(in, numinputs=0) signed char ** arrMALOut (signed char * temp) "$1=&temp;"
%typemap(in, numinputs=0) int * lMALOut (int l) "$1=&l;"
%typemap(argout) (signed char ** arrMALOut, int * lMALOut) {
    $result = JCALL1(NewByteArray, jenv, *$2);
    JCALL4(SetByteArrayRegion, jenv, $result, 0, *$2, (const jbyte*) *$1);
}
%typemap(out) bool modifyArrayLength {
    if (!$1) {
        return NULL;
    }
}


%include "arrays.h"

And finally, the Java code to test it:

public class Run{

    static {
        System.loadLibrary("Arrays");
    }

    public static void main(String[] args){

        byte[] test = arrays.createArray();

        printArray(test);       

        arrays.readArray(test);

        arrays.modifyArrayValues(test);

        printArray(test);

        byte[] test2 = arrays.modifyArrayLength(test);

        printArray(test2);

    }

    private static void printArray(byte[] arr){

        System.out.println("Array ref: " + arr);

        if(arr != null){
            System.out.println("Array length: " + arr.length);

            System.out.print("Arrays items: ");

            for(int i =0; i < arr.length; i++){
                System.out.print(arr[i] + " ");
            }
        }
        System.out.println();
    }
}

The example works, but I'm not sure if this is the right way, I mean:

is there an easier way to achieve the same result?

This code has memory leaks (on the one hand, I think it is because I am making a calloc, but I am not freeing it, but on the other hand, I am passing it to SetByteArrayRegion, so possibly freeing it will result in an error) ?

Does SetByteArrayRegion copy values โ€‹โ€‹or just a link ?, for example, if instead of actually executing a calloc, what should I do if I get an array from a C ++ object by a link that will be destroyed when I exit the area?

Is the array returned by Java correctly freed when it is invalidated?

, ?, , .i , , , , , , , , .

carrays.i, Java ++ Swig?, , 1000 , Java Socket String, 1 JNI- . byte[] Java, , .


: , , , , , , Google. , , :

class SomeLibrary {

  bool export(const std::string & sName, std::string & toExport);

  bool import(const std::string & sName, const std::string & toImport);

}

, Protobuf ++ std::string , , Java, , Swig: std::string () java- [].

, - Java a byte[] Protobuf ( Java- ) byte[] protobuf. SWIGTYPE_p_std_string String import y , % extend, :

%extend SomeLibrary{

  bool export(const std::string & sName, char ** toExportData, int * toExportLength);

  bool import(const std::string & sName, char * toImportData, int toImportLength);

}

typemaps.

, , Java SWIG, Java byte[].

+5
2

carrays.i . , SWIG :

%module test

%apply(char *STRING, size_t LENGTH) { (char *str, size_t len) };

%inline %{
void some_func(char *str, size_t len) {
}
%}

Java:

public static void some_func(byte[] str)

. , Java, , . .

, , - free() - argout, Java.

typemaps , . . . , %apply, . ( typemaps, , )

, typemaps Java ++ , ++ Java, .

, Java , : , , . :

ssize_t some_function(char *in, size_t in_sz) {
  if (in_sz < the_size_I_need) {
    return the_size_I_need; // query the size is pretty fast
  }

  // do some work on in if it big enough

  // use negative sizes or exceptions to indicate errors

  return the_size_I_really_used; // send the real size back to Java
}

- Java:

int sz = module.some_function(new byte[0]);
byte result[] = new byte[sz];
sz = module.some_function(result);

, new byte[0], null - typemaps, , , %extend , .

+5

: http://swig.org/Doc3.0/SWIGDocumentation.html#Java_binary_char

byte [] java:

%apply (char *STRING, size_t LENGTH) { (const char data[], size_t len) }
%inline %{
void binaryChar1(const char data[], size_t len) {
  printf("len: %d data: ", len);
  for (size_t i=0; i<len; ++i)
    printf("%x ", data[i]);
  printf("\n");
}
%}
0

All Articles