SirBones has asked for the wisdom of the Perl Monks concerning the following question:
Hello Monks. I'm writing a data file dumper. Gee, that's never been done in Perl before, has it? :-) I've looked around a bit for a simple answer to this, but I admit to being pretty new to pack/unpack intricacies; so I humbly beg your pardon if I'm missing something obvious.
The files in question are constructed (besides some fixed length header records) with repeating fields consisting of a 2-byte ASCII keyword, a 1-byte length (byte count), and a data field (size specified in length field.) The data field can contain either ASCII or binary data, depending on the keyword. For example:
RT | 0x07 | testing CD | 0x08 | 0x01020304FFDDEC19
Perfect for "unpack", correct? My only hangup is trying to generalize the loop that spits out the keywords and data. The data needs to be displayed as either hex or ASCII, depending on the keyword. So I have a hash which matches either an "A" or an "H" with each keyword. I then use the contents of the hash as the type specifier in the unpack template:
C/$kwfmt{$kw}
When the data is ASCII, this works fine. But when it's hex, I only get half of my string displayed because the "H" format uses the number of nibbles as its length, where my length specification is (of course) in bytes. Of course I can (and currently do) handle this in a cludgy way by checking the format during the loop and then using a different template based on "A" or "H"; but it's ugly.
I tried throwing in a repeat value after the C/$kwfmt{$kw} but of course then Perl says I can't use a count with the "/" specifier. I've also tried various means of doubling the "C" field within the template when the data is hex but that hasn't worked out either.
Here's a small demo to exemplify my dilemma. It prints the ASCII string correctly, but just half of the hex string:
#!/usr/bin/perl -w use strict; # Some example "keywords" and how they should be displayed my %kwfmt = ( "RT" => "A", "PN" => "A", "SN" => "A", "AB" => "H", "CD" => "H", "B1" => "H", ); # The kind of thing I will see in my file my @record; $record[0] = pack ("A2CA7", "RT", 7, "testing"); $record[1] = pack ("A2CH16", "CD", 8, "01020304FFDDEC19"); # Prints ASCII fields fine, truncates hex for (my $i=0; $i<2; $i++) { my ($kw) = unpack("A2", $record[$i]); my ($rdata) = unpack("x2C/$kwfmt{$kw}", $record[$i]); print "$kw $rdata\n"; }
The output of which is:
RT testing CD 01020304
As a side note, and probably displaying my ignorance, I wonder why the "H" specifier deals with nibbles as its basic unit and not bytes. Dealing with "hex" data by the byte would seem to be the far more common operation.
Thanks (as usual) so much.
Ken
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Length of unpacked string for "hex" data
by ikegami (Patriarch) on Apr 24, 2006 at 20:07 UTC | |
by SirBones (Friar) on Apr 24, 2006 at 22:52 UTC | |
by ikegami (Patriarch) on Apr 24, 2006 at 23:01 UTC | |
|
Re: Length of unpacked string for "hex" data
by wedgef5 (Scribe) on Apr 24, 2006 at 18:54 UTC | |
by SirBones (Friar) on Apr 24, 2006 at 19:54 UTC | |
|
Re: Length of unpacked string for "hex" data
by swampyankee (Parson) on Apr 24, 2006 at 21:35 UTC | |
|
Re: Length of unpacked string for "hex" data
by ikegami (Patriarch) on Apr 24, 2006 at 21:59 UTC |