locinus has asked for the wisdom of the Perl Monks concerning the following question:

Hi monks.

I'm new using unpack function to get data from an external binary source. I'm having trouble getting the right values.

My first value is coded as an unsigned 16-bit integer, little-endian. When I open it with my hex editor, I can see that the two first bytes are coded "DC 20", which represents 8412, which is the value I expect.

My perl code is the following:

my $fh = FileHandle->new; open ($fh, '<', $filename) or die 'missing file'; binmode $fh, ':raw'; my @values = unpack 'S<', $fh; print @values;

and provides the value 26950. I really can't figure out where this data comes from. Same if I provide '<:raw' to the open function.

I'm running on Windows 7 64-bit, Perl 5.12.3.

Any idea/suggestion? I'm clueless right now.

Replies are listed 'Best First'.
Re: Using unpack on Windows with external data
by dave_the_m (Monsignor) on Aug 27, 2016 at 12:02 UTC
    Unpack reads from a string, not a filehandle. You need to read from the file first. This works for me:
    my $file = $ARGV[0]; open my $fh, '<', $file or die "open: $file: $!\n"; binmode $fh, ':raw'; my $buf; my $n = read($fh, $buf, 2); die "got $n bytes\n" unless $n == 2; my @values = unpack 'S<', $buf; printf "0x%x\n", $_ for @values;

    Dave.

      That was actually the solution, thanks a lot!
      (sorry I reply only now...!)
Re: Using unpack on Windows with external data
by johngg (Canon) on Aug 27, 2016 at 21:30 UTC

    I very rarely touch the command line on Windows, I use Linux or Cygwin, but I thought I'd try unpacking from a filehandle wrapped in a do block. Create a file with some unsigned little-endian shorts:-

    C:\Users\johngg>perl -Mstrict -Mwarnings -e "print pack q{(S<)*}, 8412 + .. 8421" > littleEndian

    Check that the file has the content we expect (Windows is not my natural environment so I drop into Cygwin to use hexdump - is there an equivalent in Windows?):-

    $ hexdump -C /cygdrive/c/Users/johngg/littleEndian 00000000 dc 20 dd 20 de 20 df 20 e0 20 e1 20 e2 20 e3 20 |. . . . . + . . . | 00000010 e4 20 e5 20 |. . | 00000014

    Now unpack the content:-

    C:\Users\johngg>perl -Mstrict -Mwarnings -E "say for unpack q{(S<)*}, +do { open my $fh, q{<:raw}, shift or die $!; <$fh> };" littleEndian 8412 8413 8414 8415 8416 8417 8418 8419 8420 8421

    Using read to pull fixed length records into a buffer for processing is the best way to go but I hope this little aside is of interest.

    Cheers,

    JohnGG