views:

48

answers:

3

Hi all,

this might be quite a newbie question, but i need to process a certain text file and dump its content into a binary file and i do not know how - i decided to use perl, but my perl skills are quite low. I probably should have written this in C++, but this seem like a nice and easy task for perl, so why not learn something new? ;) The text file has thousands of lines in this format:

2A02FC42 4

You can look at it as a hexadecimal number (the length is ALWAYS 8) and a regular number. Now i need to dump all the lines into a binary file in this format (it should look like this when viewed with a hex editor):

42FC022A00000004

More examples so it is clear:

70726F67 36 -> 676F727000000024
6A656374 471 -> 7463656A000001D7

The part of parsing the input file is easy, but i'm stuck on the second part, where i should write this into a binary file. I have no idea how to format the data in this way or even how to output things in binary mode. Can someone help me out here?

Thanks.

EDIT: updated the examples, forgot about endiannes - im on a LE system.

A: 

The canonical way is to use pack. Let's suppose that the data you have read from the text file is already converted into numbers (including the hex one), and is stored in vars $x and $y. Then you should do something like

 print OUTFILE pack("NN", $x, $y);

If you require different byteorder, you will have to use different template from NN, see perldoc -f pack for details.

Grrrr
Try not use use a bare file handle; `print $outfile ....` is better.
gvkv
+6  A: 

Use pack:

#! /usr/bin/perl

use warnings;
use strict;

# demo only    
*ARGV = *DATA;

while (<>) {
  my($a,$b) = split;
  $a = join "", reverse $a =~ /(..)/g;
  $b = sprintf "%08x", $b;

  print pack "H*" => $a . $b;
}

__DATA__
2A02FC42 4
70726F67 36
6A656374 471

Sample run:

$ ./prog.pl | od -t x1
0000000 42 fc 02 2a 00 00 00 04 67 6f 72 70 00 00 00 24
0000020 74 63 65 6a 00 00 01 d7
0000030
Greg Bacon
Thanks, this works like a charm!
PeterK
@PeterK You're welcome! I'm glad it helps.
Greg Bacon
Note for the best portability, you should toggle binary mode for the output stream: `binmode(STD0UT)`
dolmen
+1  A: 

My version (tested):

my $fout;
if ( ! open( $fout, ">/tmp/deleteme.bin" ) ) {
    die( "Failed to open /tmp/deleteme.bin: $!" );
}
binmode( $fout );

while ( <DATA> ) {
    my ( $left, $right ) = split( /\s+/s, $_ );

    my $output = pack( "VN", hex($left), int($right) );
    printf(
        STDERR
        "  note, %8X %d -> " . ( "%02X" x 8 ) . "\n",
        hex($left), $right,
        map { $_ } unpack( "C8", $output )
    );

    print( $fout $output );
}
close( $fout );

__DATA__
70726F67 36 -> 676F727000000024
6A656374 471 -> 7463656A000001D7

outputs:

note, 70726F67 36 -> 676F727000000024
note, 6A656374 471 -> 7463656A000001D7
PP