|
From: William S F. <ws...@fu...> - 2009-08-07 23:08:45
|
Robin Marx wrote:
>
> Hello dear reader,
>
> My problem is quite complex, so please stay with me here. If you think :
> WOW, I'm not going to read all of this, just skip to the questions at
> the bottom and see if you can answer without reading :).
>
> I'm trying to use our in-house c++ networking library in google Android.
> For this I have generated the c++ wrapper and the needed java classes
> with SWIG.
>
> The problem is with this function from our UDPv4Socket - class : (pseudo)
> bool write( const void* data, size_t &length, ... );
>
> I searched everywhere for a good void* typemap, but I was sadly unable
> to find one.
>
> ---------------------------------------------------------------------------------------------------------------------------------------------
>
> First I tried to make an extra c++ function :
> bool write( const char* data, size_t &length, ... )
> { return write( (const void *)data, length, ... ); }
>
> resulting in java-code : socket.write( String s, ... );
>
> (I also tried it without an extra function, using %apply char[] { void*
> }, which also worked ).
>
> This worked just fine if I just tried to send something like:
> String s = "This is a test";
>
> --------------------------------------------------------------------------------------------------------------------------------------------
>
> But we don't just want to be able to write strings, but series of bytes
> (we want to use it for audio/video communications and to send other
> binary data).
>
> So I tried:
>
> byte[] data = new byte[10];
> for( int i = 0; i < 10; ++i )
> data[i] = (byte) i;
>
> String testBytes = null;
> try {
> testBytes = new String(data,"US-ASCII");
> } catch (UnsupportedEncodingException e) {
> e.printStackTrace();
> }
>
> socket.write(testBytes, ... );
>
> And there is where it all went horribly wrong...
> As it appears the String-constructor wont take the byte value 0 and will
> transform it into 2 bytes (with values c0 80 in this case). I also tried
> it with 0's on other places, same results (it replaces it with 2
> different characters). Other bytes seemed to work fine though.
>
> So this is really unwanted behaviour, because there WILL be 0's in our
> byte-data.
>
> -------------------------------------------------------------------------------------------------------------------------------------
>
> So then I found this post :
> http://www.nabble.com/Re%3A-Java-directors-and-typemaps-p18857353.html
>
> He gives some typemaps for byte[] to void*, which is of course ideal.
> Trying them out with SWIG indeed produces compilable code.
>
> So i tried (see previous testcode as well) :
> socket.write( data, ... ) (because now it expects byte[] as first
> argument and not String)
>
> And ow boy, did that give weird results... no matter what I put into the
> array it always sent the same data :
> 68 d1 00 40 00 00 0a 00 00 00 00 (in stead of 00 01 02 03 04
> ...)
>
> After a while we tried making the array a bit bigger (100 elements, from
> 0 to 99) and that's when we saw that the data was present, but only
> after 16 bytes... (the 10 bytes above being +- the first of those 16,
> padded with 4 more 00 ).
>
> And after some searching :
> http://www.codeinstructions.com/2008/12/java-objects-memory-structure.html
> (look for Memory layout of arrays ). There is stated that all java
> arrays have a header which describes it and it's length (and in our case
> probably 12 bytes header + 4 bytes padding).
>
> So ok... 16 bytes header before the data. That is NOT funny. We could
> just hard-coded change our c++ wrapper code to start at the
> void*-address + 16, but that's insanely hacky and probably not really
> portable. (even though it works...)
>
> ------------------------------------------------------------------------------------------------------------------------------------------
>
> So FINALLY the question :
>
> *Does anyone know about a good byte[] to void* mapping that wont show
> the 16 header-bytes when reading in c++ ?
> *(preferably for in AND out void* as there is also a read(void*...)
> function )*
>
> Or does someone maybe have a solution to the "java replaces 0 with
> different chars in new String(byte[])". *
>
> Both would be extremely helpful, so thanks in advance.
>
byte[] to void * can be achieved by using the signed char[] typemaps as
these map byte[] to signed char arrays. Simply use:
%include <arrays_java.i>
bool write(signed char data[], const size_t &length);
or if you want to SWIG to parse the write method's signature as taking
void *, then a little extra is required, to apply the appropriate
typemaps, plus some changes in the 'in' and 'argout' typemaps to add in
appropriate casts, as the original typemaps assume the type is signed
char *, not void *:
%include <arrays_java.i>
%typemap(in) signed char[] (jbyte *jarr)
%{ if (!SWIG_JavaArrayInSchar(jenv, &jarr, (signed char **)&$1,
$input)) return $null; %}
%typemap(argout) signed char[ANY], signed char[]
%{ SWIG_JavaArrayArgoutSchar(jenv, jarr$argnum, (signed char *)$1,
$input); %}
%apply signed char[] { const char* data }
bool write( const void* data, size_t &length);
William
|