views:

541

answers:

3

I have some 256-character strings of hexadecimal characters which represent a sequence of bit flags, and I'm trying to convert them back into a bitstring so I can manipulate them with &, |, vec and the like. The hex strings are written in integer-wide big-endian groups, such that a group of 8 bytes like "76543210" should translate to the bitstring "\x10\x32\x54\x76", i.e. the lowest 8 bits are 00001000.

The problem is that pack's "h" format works on one byte of input at a time, rather than 8, so the results from just using it directly won't be in the right order. At the moment I'm doing this:

my $bits = pack("h*", join("", map { scalar reverse $_ } unpack("(A8)*", $hex)));

which works, but feels hackish. It seems like there ought to be a cleaner way, but my pack-fu is not very strong. Is there a better way to do this translation?

A: 

Use the hex function to turn the hex string into Perl's internal representation of the number, the do your bitwise operations, then use sprintf to turn it back into the hex string:

#!/usr/bin/perl

use strict;
use warnings;

my $hex = "76543210";
my $num = hex $hex;

$num &= 0xFFFF00FF; #turn off the third byte

my $new_hex = sprintf("%08x", $num);

print "was $hex is now $new_hex\n";
Chas. Owens
The solution you propose works only for small numbers, i.e. if $hex is not longer than 8 or 16 bytes.
pts
Yeah, sorry. I wasn't clear about that in the original question. It's edited now.
wisnij
+4  A: 
my $hex = "7654321076543210";  # can be as long as needed
my $bits = pack("V*", unpack("N*", pack("H*", $hex)));
print unpack("H*", $bits);  #: 1032547610325476
pts
A: 

Have you considered using the excellent Bit::Vector?

innaM