nativelibs4java / BridJ

BridJ: blazing fast Java / C / C++ interop
https://code.google.com/archive/p/bridj/
Other
297 stars 77 forks source link

incorrect byte ordering #105

Closed psteinb closed 6 years ago

psteinb commented 6 years ago

I am doing a very simple test to bridj

@Test public void testShortPointer() throws FormatException {

        final short[] array = { (short)100, (short)101, (short)96, (short)256 };
        final Pointer<Short> sptr = pointerToShorts(array);
        assertEquals(sptr.order(),ByteOrder.LITTLE_ENDIAN);
        final Pointer<Byte> ptr = sptr.as(PointerIO.getByteInstance());
        assertEquals(ptr.order(),ByteOrder.LITTLE_ENDIAN);

        assertEquals(ptr.getByteBuffer().capacity(),8);
        assertEquals((byte)0, (byte)ptr.getByteBuffer().get(0)); //BOOM, ptr.getByteBuffer().get(0) returns 100
        assertEquals((byte)100,(byte)ptr.getByteBuffer().get(1)); //BOOM, ptr.getByteBuffer().get(1) returns 0
        //etc with the other entries
    }

Does anyone know if I am misusing the library or misunderstanding endianess? My core problem is that I am getting a Pointer<Byte> from a C API and know that it represents 16-bit unsigned short data. I am having a hard time bringing that in the right ordering in java.

royerloic commented 6 years ago

Don't play with ordering on the bridj side, instead use the ordering functions from NIO that you can find in the ByteBuffer class for example... I suspect that when returning a bytebuffer, the ordering set in BridJ is ignored... probably because the raw buffer is passed to the NIO buffer andthe ordering is really just a 'view' computed oin the fly by bridj when accessing individual values...

adibrov commented 6 years ago

As far as I understand, if you have a short value 100, it consists of two bytes: most significant 0 and least significant 100. So in case of a little endian buffer you are supposed to get 100 in the initial position.

If I change the first entry of your input array from 100 to 256 (the first value exceeding a single byte capacity), I have the least significant byte set to 0 and the most significant one - to 1. Which is what I expect to see.

Am I missing something?

psteinb commented 6 years ago

perfectly on the spot @adibrov . for one, I refreshed my understanding of endianness this morning. :/ I further investigated and saw that the core confusion didn't come from BridJ in this matter nor endianness, but rather from the ByteBuffer API and my understanding of it. First, ByteBuffer assumes BIG_ENDIAN ordering by default ... which is interesting. Never the less, I misunderstood what getShort does:

@Test public void testShortPointer() throws FormatException {

        final short[] array = { (short)100, (short)101, (short)96, (short)256 };
        final Pointer<Short> sptr = pointerToShorts(array);

        assertEquals((short)100,sptr.getByteBuffer().getShort(0));
        assertEquals((short)101,sptr.getByteBuffer().getShort(1));
        //throws: java.lang.AssertionError: expected:<101> but was:<25856>
    }

However, if you use sptr.getByteBuffer().asShortBuffer().get(1) the test passes.

psteinb commented 6 years ago

for completeness, the 2nd part of th problem were statements like:

final ByteBuffer buf = ByteBuffer.wrap(sptr.getBytes())

The ByteBuffer that is returned from the static wrap method has ByteOrder.BIG_ENDIAN ordering irrespective of the machine type this code is running on.