Question

I have a hex string (length 48 chars) that I want to convert to raw bytes with the pack function in order to put it in a Win32 vector of bytes.

How I can do this with Perl?

Was it helpful?

Solution

The steps are:

  1. Extract pairs of hexadecimal characters from the string.
  2. Convert each pair to a decimal number.
  3. Pack the number as a byte.

For example:

use strict;
use warnings;

my $string = 'AA55FF0102040810204080';
my @hex    = ($string =~ /(..)/g);
my @dec    = map { hex($_) } @hex;
my @bytes  = map { pack('C', $_) } @dec;

Or, expressed more compactly:

use strict;
use warnings;

my $string = 'AA55FF0102040810204080';
my @bytes  = map { pack('C', hex($_)) } ($string =~ /(..)/g);

OTHER TIPS

my $bytes = pack "H*", $hex;

See perlpacktut for more information.

I have the string:

"61 62 63 64 65 67 69 69 6a"

which I want to interpret as hex values, and display those as ASCII chars (those values should reproduce the character string "abcdefghij").

Typically, I try to write something quick like this:

$ echo "61 62 63 64 65 67 69 69 6a" | perl -ne 'print "$_"; print pack("H2 "x10, $_)."\n";'
61 62 63 64 65 67 69 69 6a
a

... and then I wonder, why do I get only one character back :)

First, let me note down that the string I have, can also be represented as the hex values of bytes that it takes up in memory:

$ echo -n "61 62 63 64 65 67 68 69 6a" | hexdump -C
00000000  36 31 20 36 32 20 36 33  20 36 34 20 36 35 20 36  |61 62 63 64 65 6|
00000010  37 20 36 38 20 36 39 20  36 61                    |7 68 69 6a|
0000001a

_(NB: Essentially, I want to "convert" the above byte values in memory as input, to these below ones, if viewed by hexdump:

$ echo -n "abcdefghij" | hexdump -C
00000000  61 62 63 64 65 66 67 68  69 6a                    |abcdefghij|
0000000a

... which is how the original values for the input hex string were obtained. )_

Well, this Pack/Unpack Tutorial (AKA How the System Stores Data) turns out is the most helpful for me, as it mentions:

The pack function accepts a template string and a list of values [...]

$rec = pack( "l i Z32 s2", time, $emp_id, $item, $quan, $urgent);

It returns a scalar containing the list of values stored according to the formats specified in the template [...]

$rec would contain the following (first line in decimal, second in hex, third as characters where applicable). Pipe characters indicate field boundaries.

    Offset   Contents (increasing addresses left to right)
         0   160  44  19  62| 41  82   3   0| 98 111 120 101 115  32 111 102
              A0  2C  13  3E| 29  52  03  00| 62  6f  78  65  73  20  6f  66
                                            |  b   o   x   e   s       o   f

That is, in my case, $_ is a single string variable -- whereas pack expects as input a list of several such 'single' variables (in addition to a formatting template string); and outputs again a 'single' variable (which could, however, be a sizeable chunk of memory!). In my case, if the output 'single' variable contains the ASCII code in each byte in memory, then I'm all set (I could simply print the output variable directly, then).

Thus, in order to get a list of variables from the $_ string, I can simply split it at the space sign - however, note:

$ echo "61 62 63 64 65 67 68 69 6a" | perl -ne 'print "$_"; print pack("H2", split(/ /, $_))."\n";'
61 62 63 64 65 67 68 69 6a
a

... that amount of elements to be packed must be specified (otherwise again we get only one character back); then, either of these alternatives work:

$ echo "61 62 63 64 65 67 68 69 6a" | perl -ne 'print "$_"; print pack("H2"x10, split(/ /, $_))."\n";'
61 62 63 64 65 67 68 69 6a
abcdeghij

$ echo "61 62 63 64 65 67 68 69 6a" | perl -ne 'print "$_"; print pack("(H2)*", split(/ /, $_))."\n";'
61 62 63 64 65 67 68 69 6a
abcdeghij
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top