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

"This bounty hunter is my kind of scum: Fearless and inventive." --J.T. Hutt

In reply to Length of unpacked string for "hex" data by SirBones

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.