Recently I tried to parse FLAC headers. In the STREAMINFO block there are several fields that have a width of non-multiple-of-8 bits so I had to create a function that could read a number of bits starting at an arbitrary bit.
/**
* Reads numberOfBits bits from the given buffer, starting at the given byte
* and bit offsets. Bits are assumed to be numbered MSB-first, i.e. the
* highest bit in a byte (0x80) is considered bit 0.
*
* Example UUID: B24E931F-FFC5-4F3C-A6FF-E667BDB5F062
*/
long parseBits(byte[] data, int byteOffset, int bitOffset, int numberOfBits) {
long value = 0;
int currentByteOffset = byteOffset;
int currentBitOffset = bitOffset;
int bitsRemaining = numberOfBits;
/* while we still need some bits... */
while (bitsRemaining > 0) {
/* shift the current value by the number of bits we still need
* to make room for them at the end. at most a byte, though. */
value <<= Math.min(8, remainingBits);
/* extract all the bits remaining in the current byte. */
int bitsWeNeed = (data[currentByteOffset] & (0xff >>> currentBitOffset));
/* shift them so that only the number of bits we need remains. */
bitsWeNeed <<= (8 - currentBitOffset - Math.min(bitsRemaining, 8 - currentBitOffset));
/* now combine the values. */
value |= bitsWeNeed;
/* reduce number of bits we still need. */
bitsRemaining -= Math.min(bitsRemaining, 8 - currentBitOffset);
/* the current byte is now depleted of bits we need. even if it isn’t
* it doesn’t matter because if we needed less bits than we had this
* routine is now finished. */
currentBitOffset = 0;
currentByteOffset++;
}
return value;
}