Search code examples
javatype-conversionintegerbit-manipulationbyte

Convert byte to int using bitwise operators


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.


Solution

  • 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:

    1. read the byte:

      xxxxxxxx
      
    2. expand the byte into an int:

      000000000000000000000000xxxxxxxx        
      
    3. shift the bits to the left by 16 slots:

      00000000xxxxxxxx0000000000000000
      
    4. 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)      ));
    }