views:

516

answers:

3

For example, I want to create a file called sample.bin and put a number, like 255, so that 255 is saved in the file as little-endian, FF 00. Or 3826 to F2 0E.

I tried using binmode, as the perldoc said.

+9  A: 

The perl pack function will return "binary" data according to a template.

open(OUT, '>:raw', 'sample.bin') or die "Unable to open: $!";
print OUT pack('s<',255) ;
close(OUT);

In the above example, the 's' tells it to output a short (16 bits), and the '<' forces it to little-endian mode.

In addition, ':raw' in the call to open tells it to put the filehandle into binary mode on platforms where that matters (it is equivalent to using binmode). The PerlIO manual page has a little more information on doing I/O in different formats.

Adam Batkin
wow i see thanks. im new to PERL so i think I will visit perldoc for the pack function. thanks
sasayins
pack is a nice function. Pay special attention to which template characters are for encoding little-endian vs. big-endian values
mobrule
thanks Adam and mobrule. pack is perfect! thanks
sasayins
Remember that the language is Perl and the interpreter/compiler is perl. I don't mean to be pedantic, but mis-capitalizing the language is a common problem.
Drew Stephens
@Adam, please don't use the 2-argument form of open. When paired with filenames from variables it creates a huge security hole waiting to be exploited. Using lexical filehandles is also good idea (it limits the scope of your filehandle). Your open statement should be rewritten as `open( my $out, '>', 'sample.bin') or die "Blah $!";`
daotoad
A: 

Yes, use binmode

For your entertainment (if not education) my very first attempt at creating a binary file included binmode STDOUT and the following:

sub output_word {
    $word = $_[0];
    $lsb  = $word % 256;
    $msb  = int($word/256);
    print OUT chr($lsb) . chr($msb);
    return $word;
}

FOR PITY'S SAKE DON'T USE THIS CODE! It comes from a time when I didn't know any better.

It could be argued I still don't, but it's reproduced here to show that you can control the order of the bytes, even with brain-dead methods, and because I need to 'fess up.

A better method would be to use pack as Adam Batkin suggested.

I think I committed the atrocity above in Perl 4. It was a long time ago. I wish I could forget it...

pavium
I looked at some old code recently thinking that it was awesome. It was crap, and I hadn't done much programming in the intervening 2 years. I read somewhere that if you don't think your old code is crap then there's something wrong with you. .... wish I remembered, it was a great article.
Elizabeth Buckwalter
Many thanks to whoever upvoted me. I can now delete the source file I've been hanging on to, and the healing process can begin.
pavium
If you don't like your answer, you can delete it.
brian d foy
Unfortunately now that the code is here, you'll never be freed of it. It will probably end up on some dotcom site in a year or two.. :)
Ether
Only a fragment of the code is still here and I thought it would serve as an example, a friendly *warning* for others. But the warning apparently is that if you post sub-optimal Perl code *with clear advice that it is imperfect and to be avoided*, some Perl zealot will eventually downvote it.
pavium
+3  A: 

You can use pack to generate your binary data. For complex structures, Convert::Binary::C is particularly nice.

CBC parses C header files (either from a directory or from a variable in your script). It uses the information from the headers to pack or unpack binary data.

Of course, if you want to use this module, it helps to know some C.

CBC gives you the ability to specify the endianness and sizes for your C types, and you can even specify functions to convert between native Perl types and the data in the binary file. I've used this feature to handle encoding and decoding fixed point numbers.

For your very basic example you'd use:

use strict;
use warnings;

use IO::File; 

use Convert::Binary::C;

my $c = Convert::Binary::C->new('ByteOrder' => 'LittleEndian');

my $packed = $c->pack( 'short int', 0xFF );

print $packed;

my $fh = IO::File->new( 'outfile', '>' ) 
  or die "Unable to open outfile - $!\n";

$fh->binmode;

$fh->print( $packed );

CBC doesn't really get to shine in this example, since it is just working with a single short int. If you need to handle complex structures that may have typedefs pulled from several different C headers, you will be very happy to have this tool on hand.

Since you are new to Perl, I'll suggest that you always use stict and use warnings. Also, you can use diagnostics to get more detailed explanations for error messages. Both this site and Perlmonks have lots of good information for beginners and many very smart, skilled people willing to help you.

BTW, if you decide to go the pack route, check out the pack tutorial, it helps clarify the somewhat mystifying pack documentation.

daotoad
thanks for the tips, and for the pack tutorial link :)
sasayins