gene kelley wrote:

I have an application where I need to read some header information found in 3

different types of file types. Two of the file types were fairly straight forward as

the items to read in the header are at least 8 bits (one byte), so, I'm able to step

through a file stream with a binary reader and retrive the data. The last file type,

however, has me stumped at the moment. The header spec specifies the item lengths in

bits. Most of the item lengths are 8 bit multiples which is not a problem. There

are three items, however, that are listed with less than 8 bit lengths - one as 1

bit, one as 7 bit, and another at 3 bits.

In VB, how do you read bit values?

Usually it consists on using the And operator and the Shift operators

(<< and >>). But, in the end, it all will depend on how the sequence of

elements is layed out in the byte stream.

Just to give you a starting point, consider that to read an arbitrary

amount of bits from a byte you need first to isolate the relevant bits

and align them to the lower boundary of the byte.

Suppose for instance you have a 3-bit value. The easier situation is

when the bits are already "right-aligned" in the byte:

aaaaabbb

(where 'a' represents "don't care" bits, and 'b' represents the bits

you want).

In this case you need only to mask the relevant bits with an And-mask,

that is, a sequence of n 1 bits, where n is the size of your data -- 3,

in this case:

aaaaabbb And 00000111 = 00000bbb

How to find the mask, you ask? Easy:

Dim Mask As Byte = (1 << Size) - 1

The first problem begins when the bits are not 'right-aligned' in the

byte:

aaabbbaa

To resolve this you must first put the bits in the 'right' position.

You do this by shifting the bits to right n positions, where n is the

leftmost position of the bit pattern plus one, minus the size of the

pattern:

Dim Shift As Byte = LeftmostBit + 1 - Size

Value = Value >Shift

Notice, however, that the bit positions are numbered like this:

76543210

Therefore, in the previous example, the leftmost bit would be 4.

So, to put it all together so far you'd have something like:

<aircode>

Function GetBits(Value as Byte, _

LeftmostBit As Byte, _

Size as Byte) As Byte

Dim Shift As Byte = LeftmostBit + 1 - Size

Dim Mask As Byte = (1 << Size) - 1

Return (Value >Shift) And Mask

End Function

</aircode>

Probably, depending on your settings, VB will give you all types of

warnings, because in the above expressions the value "1" is computed as

an integer, and the entire expression is promoted to integer. Getting

rid of the warnings remains as an exercise =))

Finally, things become *really* complicated when you have a stream of

values whose bits span two bytes:

aaaaaabb baaaaaaaa

To resolve this, you must treat the two bytes as a 16 bit value (a

Short, in VB). When you do this, everything else Just Works (TM), as

long as you treat the leftmost bit position as a number from 0 to 15

(and not 0 to 7, as in the previous example). If we use hexadecimal to

represent the bit positions, we'd have:

FEDCBA98 76543210

Therefore, in the above example, our leftmost bit would be 9 !

A function that would extract a given bit pattern from a sequence of

two bytes could be like this:

<aircode>

Function GetBits(FirstByte As Byte, _

ScndByte As Byte, _

LeftmostBit As Byte, _

Size As Byte) As Byte

Dim Value As Integer = (CInt(FirstByte) << 8) Or ScndByte

Dim Shift As Integer = LeftmostBit + 1 - Size

Dim Mask As Integer = (1 << Size) - 1

Dim Result As Integer = (Value >Shift) And Mask

Return CByte(Result And 255)

End Function

</aircode>

HTH.

Regards,

Branco.