Question

I'm trying to write a script to find hex strings in a text file and convert them to their reverse byte order. The trouble I'm having is that some of the hex strings are 16 bit and some are 64 bits. I've used Perl's pack to pack and unpack the 16 bit hex numbers and that works fine, but the 64 bit does not.

print unpack("H*", (pack('I!', 0x20202032))). "\n"; #This works, gives 32202020
#This does not
print unpack("H*", (pack('I!', 0x4f423230313430343239303030636334))). "\n";

I've tried the second with the q and Q (where I get ffffffffffffffff). Am I approaching this all wrong?

As bit of background, I've got a multi-gigabyte pipe-delimited text file that has hex strings in reverse byte order as explained above. Also, the columns of the file are not standard; sometimes the hex strings appear in one column, and sometimes in another. I need to convert the hex strings to their reverse byte order.

Was it helpful?

Solution

Always use warnings;. If you do, you'll get the following message:

Integer overflow in hexadecimal number at scratch.pl line 8.
Hexadecimal number > 0xffffffff non-portable at scratch.pl line 8.

These can be resolved by use bigint; and by changing your second number declaration to hex('0x4f423230313430343239303030636334').

However, that number is still too large for pack 'I' to be able to handle.

Perhaps this can be done using simple string manipulation:

use strict;
use warnings;

my @nums = qw(
    0x20202032
    0x4f423230313430343239303030636334
);

for (@nums) {
    my $rev = join '', reverse m/([[:xdigit:]]{2})/g;
    print "$_ -> 0x$rev\n"
}

__END__

Outputs:

0x20202032 -> 0x32202020
0x4f423230313430343239303030636334 -> 0x3463633030303932343034313032424f

Or to handle digits of non-even length:

my $rev = $_;
$rev =~ s{0x\K([[:xdigit:]]*)}{
    my $hex = $1;
    $hex = "0$hex" if length($hex) % 2;
    join '', reverse $hex =~ m/(..)/g;
}e;
print "$_ -> $rev\n"

OTHER TIPS

To be pedantic, the hex numbers in your example are 32-bit and 128-bit long, not 16 and 64. If the longest one was only 64-bit long, you could successfully use the Q pack template as you supposed (provided hat your perl has been compiled to support 64-bit integers).

The pack/unpack solution can be used anyway (if with the addition of a reverse - you also have to remove the leading 0x from the hex strings or trim the last two characters from the results):

print unpack "H*", reverse pack "H*", $hex_string;

Example with your values:

perl -le 'print unpack "H*", reverse pack "H*", "4f423230313430343239303030636334"'
3463633030303932343034313032424f
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top