Packing/Unpacking bit fields from a byte.

  • Thread starter Shashank R Khanvilkar
  • Start date
S

Shashank R Khanvilkar

Hi,
All help appreciated.

I have to parse a file which has a header. This header is say 4 bytes long
and contains many fields which are not byte aligned. For example

struct header {
#fieldname: Size(bits)
fld1: 12
fld2: 1
fld3: 2
....
}

I have already written a lengthy routing to unpack these fileds from the
header (using shifts and masks). However i was wondering if the same could
have been achieved using the pack and unpack functions?
For example:

@hdr = unpack("B12B1B2....", $header);

I find that this does not work.
Does anyone know how this can be done.

To complicate the problem fursther, how can the same be achieved for any
aribitary length header (say 15 bytes).

Thanks
Shashank
 
T

Tad McClellan

Shashank R Khanvilkar said:
say 4 bytes long
and contains many fields which are not byte aligned.

I have already written a lengthy routing to unpack these fileds from the
header (using shifts and masks).


perldoc -f vec
 
B

Bob Walton

Shashank R Khanvilkar wrote:

....
I have to parse a file which has a header. This header is say 4 bytes long
and contains many fields which are not byte aligned. For example

struct header {
#fieldname: Size(bits)
fld1: 12
fld2: 1
fld3: 2
...
}

I have already written a lengthy routing to unpack these fileds from the
header (using shifts and masks). However i was wondering if the same could
have been achieved using the pack and unpack functions?
For example:

@hdr = unpack("B12B1B2....", $header);

I find that this does not work.

Why do you think that doesn't work? It seems to work to me:

C:>perl -MData::Dumper -e "print Dumper unpack 'B12B1B2','abcd'"
$VAR1 = '011000010110';
$VAR2 = '0';
$VAR3 = '01';

C:\Temp>
....
 
S

Shashank R Khanvilkar

Shashank R Khanvilkar wrote:

...

Why do you think that doesn't work? It seems to work to me:

C:>perl -MData::Dumper -e "print Dumper unpack 'B12B1B2','abcd'"
$VAR1 = '011000010110';
$VAR2 = '0';
$VAR3 = '01';
Thanks.. I guess it is taking the ascii values of a(=61 = 0x01100001)..

Thanks for your help
Shank
 
S

Shashank Khanvilkar

Hi,

I just found that the below solution may not work for me. Here is a test
case.

for example:
perl -MData::Dumper -e "print Dumper unpack 'B4B4B4B4B*','abcd'"
$VAR1 = '0110';
$VAR2 = '0110';
$VAR3 = '0110';
$VAR4 = '0110';
$VAR5 = '';

Here the string abcd corresponds to 4 ascii characters.
a = 0x61 = 0110 0001
b = 0x62 = 0110 0010
c = 0x63 = 0110 0011
d = 0x64 = 0110 0100

So i want the output to print something like
$VAR1 = '0110';
$VAR2 = '0001';
$VAR3 = '0110';
$VAR4 = '0011';
$VAR5 = '0110001101100100';

I gues the unpack function seeks byte boundaries for every conversion.
Will appreciate if someone can verify this.
All alternate solutions are also welcome.
Shank






Shashank R Khanvilkar wrote:

...

Why do you think that doesn't work? It seems to work to me:

C:>perl -MData::Dumper -e "print Dumper unpack 'B12B1B2','abcd'"
$VAR1 = '011000010110';
$VAR2 = '0';
$VAR3 = '01';
Thanks.. I guess it is taking the ascii values of a(=61 = 0x01100001)..

Thanks for your help
Shank
 
S

Shashank Khanvilkar

Thanks
I have already checked out vector. It does not help.
Howver I now found out that the following works.

@headerFeilds = unpack("A12A1A2....", unpack("B*", $header));

The innermost unpack first converts the header to a string of bits.
the outer unpack just seperates out these bits into the fields.


Let me know if there is anything better than this.
Shashank
 
A

Anno Siegel

Ugh, top posting.
Thanks
I have already checked out vector. It does not help.

Sure? vec() (not vector) gives you access to the individual bits of a
bit string, which is what you want.
Howver I now found out that the following works.

@headerFeilds = unpack("A12A1A2....", unpack("B*", $header));

The innermost unpack first converts the header to a string of bits.
the outer unpack just seperates out these bits into the fields.

Here is one way using vec():

my $i = 0;
my @fields = map join( '', map vec( $header, $i ++, 1), 1 .. $_),
12, 1, 2;

There is no programming-around the quirks of unpack(), it accesses
each individual bit as directly as vec() allows. It's longer, but
so would be the unpack()-solution if it had to build the pack format
from parameters.

Pack and unpack are powerful, but not easy to use. Many Perl programmers
feel it's enough to know the possibilities but avoid them if there is
an alternative.

Anno
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,045
Latest member
DRCM

Latest Threads

Top