Search code examples
javabit-manipulationbyte-shifting

How to fill high-end bits in a Java byte with '1' without knowing the last 1 in advance? (FAST FIX Negative Integer decoder)


I am writing a FIX/FAST decoder for negative numbers as described below:

enter image description here

My question is:

How to fill the high-end bits of a Java byte with 1s as it is described above? I am probably unaware of some bit manipulation magic I need to in this conversion.

So I need to go from 01000110 00111010 01011101 to 11110001 10011101 01011101.

I know how to shift by 7 to drop the 8th bit. What I don't know is how to fill the high-end bits with 1s.


Solution

  • It seems like the question you're asking doesn't really match up with the problem you're trying to solve. You're not trying to fill in the high bits with 1; you're trying to decode a stop-bit-encoded integer from a buffer, which involves discarding the sign bits while combining the payload bits. And, of course, you want to stop after you find a byte with a 1 in the stop bit position. The method below should decode the value correctly:

    private static final byte SIGN_BIT = (byte)0x40;
    private static final byte STOP_BIT = (byte)0x80;
    private static final byte PAYLOAD_MASK = 0x7F;
    
    public static int decodeInt(final ByteBuffer buffer) {
        int value = 0;
        int currentByte = buffer.get();
    
        if ((currentByte & SIGN_BIT) > 0)
            value = -1;
    
        value = (value << 7) | (currentByte & PAYLOAD_MASK);
        if ((currentByte & STOP_BIT) != 0)
            return value;
    
        currentByte = buffer.get();
        value = (value << 7) | (currentByte & PAYLOAD_MASK);
        if ((currentByte & STOP_BIT) != 0)
            return value;
    
        currentByte = buffer.get();
        value = (value << 7) | (currentByte & PAYLOAD_MASK);
        if ((currentByte & STOP_BIT) != 0)
            return value;
    
        currentByte = buffer.get();
        value = (value << 7) | (currentByte & PAYLOAD_MASK);
        if ((currentByte & STOP_BIT) != 0)
            return value;
    
        currentByte = buffer.get();
        value = (value << 7) | (currentByte & PAYLOAD_MASK);
        return value;
    }
    

    A loop would be cleaner, but I unrolled it manually since messaging protocols tend to be hot code paths, and there's a fixed maximum byte length (5 bytes). For simplicity's sake, I read the bytes from a ByteBuffer, so you may need to adjust the logic based on how you're reading the encoded data.