perl

pack function cannot pack more than 5 bytes


When I try to pack more than 5 bytes using "H2" template, I can unpack the first 5 correctly but the rest are corrupted. Consider the script below:

my $a = "11:22:33:44:55:66";
my @b = split /:/, $a;
my @c = map {hex($_)} @b;

my $d = pack( 'H2'x6, @c );

my @e = unpack( 'H2'x6, $d);
foreach (@e) {
    printf("%02x:", $_);
}

Outputs: 11:22:33:44:55:0a:

The last byte is output as "0a" and not "66" as I would have expected.


Solution

  • Use Data::Dumper to see what your variables contain:

    #!/usr/bin/perl
    use strict;
    use warnings;
    
    use Data::Dumper;
    
    my $A = "11:22:33:44:55:66";  # $a is a special variable, don't use it.
    my @b = split /:/, $A;
    warn Dumper \@b;
    
    my @c = map hex, @b;
    warn Dumper \@c;
    
    my $d = pack 'H2' x 6, @c;
    {   local $Data::Dumper::Useqq = 1;
        warn Dumper $d;
    }
    
    
    my @e = unpack 'H2' x 6, $d;
    warn Dumper \@e;
    
    for (@e) {
        printf("%02x:", $_);
    }
    

    The output:

    $VAR1 = [
              '11',
              '22',
              '33',
              '44',
              '55',
              '66'
            ];
    $VAR1 = [
              17,
              34,
              51,
              68,
              85,
              102
            ];
    $VAR1 = "\0274Qh\205\20";
    $VAR1 = [
              '17',
              '34',
              '51',
              '68',
              '85',
              '10'
            ];
    11:22:33:44:55:0a:
    

    The value 102 is too long to be packed as H2, so it's truncated. You only get 10, which corresponds to \20 octal, i.e. character 16, which in hex is 10, which again interpreted as hex is 0a.

    It's possible you assumed hex converts a number to hex, but it does the opposite. Maybe you originally wanted this instead?

    #!/usr/bin/perl
    use strict;
    use warnings;
    
    use Data::Dumper;
    
    my $A = "11:22:33:44:55:66";
    my @b = split /:/, $A;
    warn Dumper \@b;
    
    my @c = map sprintf('%02x', $_), @b;
    warn Dumper \@c;
    
    my $d = pack 'H2' x 6, @c;
    {   local $Data::Dumper::Useqq = 1;
        warn Dumper $d;
    }
    
    
    my @e = unpack 'H2' x 6, $d;
    warn Dumper \@e;
    
    print hex, ':' for @e;