Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hello everyone again, I recently posted here with some help from ikegami, but I am still unable to produce the correct checksum (I am trying to match it to the checksum provided by my coworker). I would like to raed each 32 bit chunk of binary, and then turn it to decimal value, and add it to the checksum (which starts at 0). Does my ($n = read FILE, $buffer, 4) work? Is that reading 32 bits? Also, does my restraining work at the end of the script? Thanks for any and all help.
#!/usr/bin/perl -w use strict; use FileHandle; use warnings; my $data = "../file.bin"; my $buffer; my $string; my $n = 0; my $checksum = 0; my $num = 0; my $str = unpack("B32", pack("N", shift)); my $bits = 4; my $decimal; open FILE, $data or die $!; binmode FILE; while (($n = read FILE, $buffer, 4)) { $decimal = unpack("N", pack("B32", $buffer)); {$checksum = $checksum + $decimal; #$num = $num + $bits; #print "1. $num\n"; print "2. $decimal\n"; #print "3. $n bytes read\n"; print "4. $checksum \n"; } $checksum %= 2**32; }
Whenever i run this script, the number is never correct. Are there any obvious errors here?

Replies are listed 'Best First'.
Re: Difficulty producing correct checksum
by spazm (Monk) on Jul 16, 2009 at 16:18 UTC
    your read statement should be correct, since you've used binmode on the filehandle and don't have a :utf8 pragma. you're reading 4 x 8bit bytes.

    The final read is not guaranteed to be 32 bits, you should check $n to see how many bytes were read from the stream. I'm not sure of the behavior of unpack if you don't feed it enough data. Since you're using Big-Endian, it may see your final read as much larger than expected.

    Your final line $checksum %= 2^32, is going to constrain your checksum to be mod 2^32. If that's what you want, then, yes, it should work.

    You're doing your bit match in Big-Endian. Is there any chance that the code you're trying to match does it little-endian? Your B in unpack and N in pack match endianness, so that's good.

    Suggestion: make a 4 byte test file and run the other checksum program on it. Use this as the basis for your first test of your checksum program. Then progress to a 5 yte test file, to test the question about the truncated final read.

    perldoc read:

    Note the characters: depending on the status of the filehandle, either (8-bit) bytes or characters are read. By default all filehandles operate on bytes, but for example if the filehandle has been opened with the :utf8 I/O layer (see "open", and the open pragma, open), the I/O will operate on UTF-8 encoded Unicode characters, not bytes.
      Hey! thanks for all of your help guys! it finally works!
        What were the issues and how did you fix them?
        Let's see the final code!
Re: Difficulty producing correct checksum
by jrsimmon (Hermit) on Jul 16, 2009 at 16:01 UTC

    Have you considered simply using the checksum feature of unpack itself?

    In addition to fields allowed in pack(), you may prefix a field with a %<number> to indicate that you want a <number>-bit checksum of the items instead of the items themselves. Default is a 16-bit checksum. Checksum is calculated by summing numeric values of expanded values (for string fields the sum of "ord($char)" is taken, for bit fields the sum of zeroes and ones).
    Or, if that isn't what you're trying to accomplish, what about Digest::MD5 or Digest::Adler32?
Re: Difficulty producing correct checksum
by Anonymous Monk on Jul 16, 2009 at 16:06 UTC
    Does my ($n = read FILE, $buffer, 4) work? Is that reading 32 bits?
    yes, it's reading 4 characters(if 1 character=1 byte)=> 32bits

     $decimal = unpack("N", pack("B32", $buffer));
    what are you trying to do here ? you said "turn it to decimal value", you mean ascii code ? if so consider using ord