From: William S F. <ws...@fu...> - 2012-09-07 06:19:29
|
On 04/09/12 22:09, Adam B wrote: > Hello all, > > I'm trying to figure out how to apply multiple typemaps to a single C > function. Let's say I have a C function like this: > > void writeBytes(unsigned char * theBytes, int size); > > My goal is to make the target language(s) pass in raw bytes, instead of > a string so I do what the SWIG docs tell me to: > > ------------- mymodule.i ------------ > %module mymodule > > %apply (char *STRING, size_t LENGTH) { (unsigned char * theBytes, > int size) }; > void writeBytes(unsigned char * theBytes, int size); > > ----------------------------------------- > > This works perfectly. Both Python and Java are able to pass in raw bytes. > > But then I realized that if my java program passes in a 'null' > byte-array the JVM segfaults in the JNI code when calling > GetByteArrayElements(). To fix this I would like to have SWIG generate > a null-check for me using the 'javain' typemap. (Note: the NONNULL > typemap provided by constraints.i doesn't work because it does the check > too late - after GetByteArrayElements is called.) > > This typemap generates a null-check in the java proxy class code exactly > where I want it. > > ------------- mymodule.i ------------ > %module mymodule > > %typemap(javain, pre="if ($javainput == null) throw new > NullPointerException();") unsigned char * theBytes "$javainput"; > void writeBytes(unsigned char * theBytes, int size); > > ----------------------------------------- > > My question is, how do I apply BOTH these typemaps to the function. > Simply listing them both is the intuitive solution but it does not work. > > ------------- mymodule.i ------------ > %module mymodule > > //Doesn't work! > %apply (char *STRING, size_t LENGTH) { (unsigned char * theBytes, > int size) }; > %typemap(javain, pre="if ($javainput == null) throw new > NullPointerException();") unsigned char * theBytes "$javainput"; > void writeBytes(unsigned char * theBytes, int size); > > ----------------------------------------- > > The typemap should be defined before %apply in order for it to be applied and it should be defined for (char *STRING, size_t LENGTH): %typemap(javain, pre="if ($javainput == null) throw new NullPointerException();") (char *STRING, size_t LENGTH) "$javainput"; %apply (char *STRING, size_t LENGTH) { (unsigned char * theBytes, int size) }; Really the 'in' typemap should handle null as input so I've fixed this for the next release. However, I've changed it to accept NULL for the char * parameter without segfaulting in the JNI marshalling. But you don't want to accept NULL as input, so you could instead check for this in the 'in' typemap. You can simply override the default one supplied by SWIG and use: %typemap(in) (char *STRING, size_t LENGTH) { if (!$input) { SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "$1_name is null"); return $null; } $1 = (char *) JCALL2(GetByteArrayElements, jenv, $input, 0); $2 = (size_t) JCALL1(GetArrayLength, jenv, $input); } %apply (char *STRING, size_t LENGTH) { (unsigned char * theBytes, int size) }; William |