Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

PERL Binary Data Handling

by ashes3d (Initiate)
on Oct 05, 2012 at 20:01 UTC ( #997536=perlquestion: print w/ replies, xml ) Need Help??
ashes3d has asked for the wisdom of the Perl Monks concerning the following question:

Hello All, I am a PERL newbie, and come from a hardware background. My question is with regards concatenating binary data in PERL. I am reading a 32-bit value (4 bytes) from a binary file. I would like to concatenate one bit in front of the value (new value will be 33 bits!) I have tried different variations of using pack, but either I don't think I understand pack command correctly, or B, PERL doesn't like my use of a 33 bit data. How should I fix this? Here is sample of what I am doing

open (PARSER_FILE, $inputfile) or die "Couldn't open $inputfile for reading"; binmode(PARSER_FILE); open (OUT_FILE, ">", $outputfile) or die "Couldn't open $outputfile for writing"; binmode(OUT_FILE); read(PARSER_FILE, $buff, 4) . . print OUT_FILE pack(b33, 1, $buff);

Comment on PERL Binary Data Handling
Download Code
Re: PERL Binary Data Handling
by Anonymous Monk on Oct 05, 2012 at 20:55 UTC

    Sample input? Expected output?

    I usually try to figure this out with real data, something where you know what result you're expecting, along the lines of

    $ perl -le " print join q/ /, unpack q/(A4)*/, unpack q/B*/, pack q/B +33/, 1, 66 " 1000 0000 0000 0000 0000 0000 0000 0000 0000 0000 $ perl -le " print join q/ /, unpack q/(A2)*/, unpack q/H*/, pack q/B3 +3/, 1,66 " 80 00 00 00 00

    or maybe

    $ perl -le " print join q/ /, unpack q/(A2)*/, unpack q/H*/, pack q/B3 +3/, join q//, 1, unpack q/B32/, 66 " 9b 1b 00 00 00 $ perl -le " print join q/ /, unpack q/(A4)*/, unpack q/B*/, pack q/B3 +3/, join q//, unpack(q/B1/,1), unpack q/B32/, 66 " 1001 1011 0001 1011 0000 0000 0000 0000 0000 0000

    or even

    $ perl -le " print join q/ /, unpack q/(A4)*/, unpack q/B*/, pack q/B3 +3/, join q//, unpack(q/B1/,1), unpack q/B32/, 66 " 0001 1011 0001 1011 0000 0000 0000 0000 0000 0000
Re: PERL Binary Data Handling
by Illuminatus (Curate) on Oct 05, 2012 at 21:07 UTC
    First of all, I want to congratulate you, as a newbie, for utilizing code tags :).

    1. While you may want 33 bits worth of data, when you write it, it will be 40-bits worth of data. You would be best served by explicitly defining all 40 bits in your pack operation
    2. pack takes string parameters. You're reading in a binary value, and passing that as the argument to pack. To do what you want, you should my $str = unpack ("b32", $buff); and then use $str as the second arg
    3. You probably want to use syswrite to do your output, rather than print

    fnord

      Thank you both for the response! To elaborate on my question, let's assume that the input file contains a binary number of:

      "0101_1111_1111_0000_0111_0000_1111_1010"

      Output should be:

      "1_0101_1111_1111_0000_0111_0000_1111_1010"

      This is purely binary input. I only added the "_" for readability. I understand that we cannot write a file on non byte boundaries. So if I would always have 7 extra bits when this is written to the file. This would mean that my output file will look like:

      "0000_0001_0101_1111_1111_0000_0111_0000_1111_1010"

      When I run the code below, I get an output of:

      "0000_0001_0000_0000_0000_0000_0000_0000_0000_0000"

      I think I am still misusing the pack command. What am I missing? Code below:

      #!/usr/bin/perl my $inputfile = $ARGV[0]; my $outputfile = $ARGV[1]; my $buff = ""; my $mybuff = ""; open (PARSER_FILE, $inputfile) or die "Couldn't open $inputfile for reading"; binmode(PARSER_FILE); open (OUT_FILE, ">", $outputfile) or die "Couldn't open $outputfile for writing"; binmode(OUT_FILE); read(PARSER_FILE, $buff, 4); $outbuff = unpack("b32", $buff); syswrite OUT_FILE, pack("b33", 1, $outbuff); close(OUT_FILE); close(PARSER_FILE)

        G'day ashes3d,

        Welcome to the monastery.

        Using the data you've provided, here's a blow-by-blow account of how to achieve what I believe you're after.

        #!/usr/bin/env perl use 5.010; use strict; use warnings; # Simulate the 4 bytes of input binary data (i.e. from input file) my $in_data = pack 'B32' => '01011111111100000111000011111010'; # Create new leading byte with binary value of 1 my $lead_byte = pack 'B8' => '00000001'; # Concatenate leading and input bitstrings my $concat_bitstrings = unpack('B8', $lead_byte) . unpack('B32', $in_d +ata); # Create new data with 5 (1+4) bytes my $out_data = pack 'B40' => $concat_bitstrings; # Test it worked # Converting "0101_1111_1111_0000_0111_0000_1111_1010" # and "0000_0001_0101_1111_1111_0000_0111_0000_1111_1010" # to HEX format for ease of visualising/checking my $in_hex = '5ff070fa'; my $out_hex = '01' . $in_hex; # Print expected and actual results say 'Input'; say 'EXPECT: ', $in_hex; say 'GOT: ', unpack 'H*' => $in_data; say 'Output'; say 'EXPECT: ', $out_hex; say 'GOT: ', unpack 'H*' => $out_data;

        Output:

        $ pm_bin_32_40.pl Input EXPECT: 5ff070fa GOT: 5ff070fa Output EXPECT: 015ff070fa GOT: 015ff070fa

        I'll assume you've found the doco for pack and unpack. There's also a tutorial you may not be aware of: perlpacktut.

        -- Ken

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://997536]
Approved by kcott
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others rifling through the Monastery: (8)
As of 2014-09-19 04:46 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    How do you remember the number of days in each month?











    Results (129 votes), past polls