intiha
intiha

Reputation: 319

How can I parse space separated STDIN hex strings unpacked in Perl?

I have a Java program that spits out, in space-separated hexadecimal format, 16 bytes of raw packet received over the network. Since I dont want to change that code, I am piping the result to a Perl script that, theoretically, can simply unpack this from STDIN into recognizable variables. The following is a sample of the line input to my Perl file:

FF FF 09 7D 10  01  07  01 00  02 00  1D 00  00 00  00 00  06 00  07 00 
|--garbage-----|c--|c--|int---|int---|int---|int---|int---|int---|int---|

(c is for char/byte, int for 16bit integer variable)

I initially wanted to use unpack to cleanly separate each input line into variables that I needed. However, because of the space delimit in the string, I am not sure how to handle it (I can use 'A' as a template, but then I might as well just use split!)

Is there a elegant way of using unpack()? I am not a Perl master, but the other way is to, as I suggested before, use split and then manually convert each hex to a byte, and then use bit manipulations and masks to get what I want. Any other suggestions (if unpack doesnt save the day)?

Upvotes: 6

Views: 1505

Answers (2)

Greg Bacon
Greg Bacon

Reputation: 139421

Assuming those ints are in big-endian order, use

#! /usr/bin/perl

use warnings;
use strict;

# for demo only
*ARGV = *DATA;

while (<>) {
  my @fields = unpack "x5C2n7",
               pack "C*",
               map hex, split;

  print "[", join("][" => @fields), "]\n";
}

__DATA__
FF FF 09 7D 10 01 07 01 00 02 00 1D 00 00 00 00 00 06 00 07 00

It starts off by packing in the bytes (C*) according to their values. The unpack template has the following parts:

  • x5 skips five bytes
  • C2 decodes two unsigned char values
  • n7 decodes seven 16-bit big-endian unsigned integers

Output:

$ ./dump-packets
[1][7][256][512][7424][0][0][1536][1792]

Upvotes: 8

Porculus
Porculus

Reputation: 1209

If you want to use unpack on unpacked data, you'll need to pack it again first. And you'll need to remove the spaces before you do that.

In other words,

$line =~ tr/ //d;          # remove spaces
$line = pack 'H*', $line;  # convert hex to binary
# Now you can use unpack.

Upvotes: 3

Related Questions