I'm documenting some code in Java. The goal is to read and process an OSRM file which is a file containing hex codes.
The flow is as follows: Read in some byte to a ByteBuffer
using a FileChannel
. Once the buffer is filled, convert every byte to a signed integer. This is done using the bitwise &
operator and the signed left shift operator <<
, and looks like this:
return (0x000000ff & (bb.get() << 0)) |
(0x0000ff00 & (bb.get() << 8)) |
(0x00ff0000 & (bb.get() << 16)) |
(0xff000000 & (bb.get() << 24));
Where bb
is of course the ByteBuffer
.
I have totally no clue how and why this code works, I Googled a bit and the closest thing I found was the following Stack Overflow question: Converting Java method to C#: converting bytes to integers with bit shift operators.
Still, I have no clue and I'm wondering if someone could help me figure out this code snippet.
This reads four bytes from the underlying byte buffer and stitches them together into an int
value like this:
11111111 (first byte read)
22222222 (second byte read)
33333333 (third byte read)
44444444 (fourth byte read)
To achieve that, a bitwise OR operation is performed on all subresults, where each subresult prepares one row in the above diagram. For example, the third row is prepared as
(0x00ff0000 & (bb.get() << 16))
which does the following:
read the byte:
xxxxxxxx
expand the byte
into an int
:
000000000000000000000000xxxxxxxx
shift the bits to the left by 16 slots:
00000000xxxxxxxx0000000000000000
finally, push this through an AND mask which lets only the x
bits through. This is needed because byte
is signed, so the conversion to int
may actually result in the following:
111111111111111111111111xxxxxxxx
The code would perhaps be simpler if a constant AND-mask was performed before shifting:
(bb.get() & 0xFF) << 16
This is actually the standard idiom for Java in these bit-twiddling operations.
Although not an answer to the question you have asked, using the provided API would certainly be preferred (the getInt
method). Your byte order is little endian, so you would just need to set it up:
bb.order(ByteOrder.LITTLE_ENDIAN);
For reference, this is the JDK's implementation of the same code:
static private int makeInt(byte b3, byte b2, byte b1, byte b0) {
return (((b3 ) << 24) |
((b2 & 0xff) << 16) |
((b1 & 0xff) << 8) |
((b0 & 0xff) ));
}