Unpack and checksums

Discussion in 'Perl Misc' started by Fatted, May 26, 2004.

  1. Fatted

    Fatted Guest

    I'm trying to get unpack to generate a checksum but the result is always 0.
    E.G.

    my $string = 'ThisIsAString';

    my $chksum = unpack("%H*",$string);

    print $chksum."\n";


    Results in 0.

    perlfunc says unpack will generate the checksum (default 16 bit) if the
    template is preceded by %.
    What am I missing?
    Fatted, May 26, 2004
    #1
    1. Advertising

  2. Fatted

    Anno Siegel Guest

    Fatted <> wrote in comp.lang.perl.misc:
    > I'm trying to get unpack to generate a checksum but the result is always 0.
    > E.G.
    >
    > my $string = 'ThisIsAString';
    >
    > my $chksum = unpack("%H*",$string);
    >
    > print $chksum."\n";
    >
    >
    > Results in 0.
    >
    > perlfunc says unpack will generate the checksum (default 16 bit) if the
    > template is preceded by %.
    > What am I missing?


    There seems to be a bug in unpack, which appears to return a spurious
    0 with the "%H" format. Try

    perl -le 'print join( " | ", unpack "%H*", "a")'

    to see it. As a workaround, use

    my ( $chksum) = unpack("%H*",$string);

    Anno
    Anno Siegel, May 26, 2004
    #2
    1. Advertising

  3. Fatted

    fifo Guest

    At 2004-05-26 10:29 +0000, Anno Siegel wrote:
    > There seems to be a bug in unpack, which appears to return a spurious
    > 0 with the "%H" format. Try
    >
    > perl -le 'print join( " | ", unpack "%H*", "a")'
    >
    > to see it. As a workaround, use
    >
    > my ( $chksum) = unpack("%H*",$string);
    >


    Isn't this just the same as doing

    my $chksum = unpack("H*",$string);

    as unpack "H*" is only going to give you a single scalar anyway?
    fifo, May 26, 2004
    #3
  4. Fatted

    Anno Siegel Guest

    fifo <> wrote in comp.lang.perl.misc:
    > At 2004-05-26 10:29 +0000, Anno Siegel wrote:
    > > There seems to be a bug in unpack, which appears to return a spurious
    > > 0 with the "%H" format. Try
    > >
    > > perl -le 'print join( " | ", unpack "%H*", "a")'
    > >
    > > to see it. As a workaround, use
    > >
    > > my ( $chksum) = unpack("%H*",$string);
    > >

    >
    > Isn't this just the same as doing
    >
    > my $chksum = unpack("H*",$string);
    >
    > as unpack "H*" is only going to give you a single scalar anyway?


    We're not talking "H*" but "%H*". There's a *bug*, and it doesn't
    behave according to specification.

    Please read for comprehension.

    Anno
    Anno Siegel, May 26, 2004
    #4
  5. Fatted

    Fatted Guest

    Anno Siegel wrote:

    > fifo <> wrote in comp.lang.perl.misc:
    >
    >>Isn't this just the same as doing
    >>
    >> my $chksum = unpack("H*",$string);
    >>
    >>as unpack "H*" is only going to give you a single scalar anyway?

    >
    >
    > We're not talking "H*" but "%H*". There's a *bug*, and it doesn't
    > behave according to specification.
    >
    > Please read for comprehension.
    >
    > Anno


    I don't think I follow either :(

    take:

    my $string = 'ThisIsAString';
    # PERFORM PLAIN UNPACK
    my $chksum = unpack("H*",$string)."\n";
    print $chksum."\n";

    gives:
    54686973497341537472696e67

    try:

    my $string = 'ThisIsAString';
    # PERFORM CHECKSUM UNPACK
    my $chksum = unpack("%H*",$string);
    print $chksum."\n";

    gives:
    0
    as discussed

    try suggested workaround:

    my $string = 'ThisIsAString';
    # PERFORM WORKAROUND CHECKSUM UNPACK
    my ($chksum) = unpack("%H*",$string);
    print $chksum."\n";

    gives:
    54686973497341537472696e67
    which is the same result as the plain unpack and not the checksum sought.
    Fatted, May 26, 2004
    #5
  6. Fatted

    fifo Guest

    At 2004-05-26 11:12 +0000, Anno Siegel wrote:
    > fifo <> wrote in comp.lang.perl.misc:
    > > At 2004-05-26 10:29 +0000, Anno Siegel wrote:
    > > > There seems to be a bug in unpack, which appears to return a spurious
    > > > 0 with the "%H" format. Try
    > > >
    > > > perl -le 'print join( " | ", unpack "%H*", "a")'
    > > >
    > > > to see it. As a workaround, use
    > > >
    > > > my ( $chksum) = unpack("%H*",$string);
    > > >

    > >
    > > Isn't this just the same as doing
    > >
    > > my $chksum = unpack("H*",$string);
    > >
    > > as unpack "H*" is only going to give you a single scalar anyway?

    >
    > We're not talking "H*" but "%H*". There's a *bug*, and it doesn't
    > behave according to specification.
    >
    > Please read for comprehension.


    I agree that there's a bug with "%H*". The point I was trying to make
    was that "%H*" doesn't do anything useful over "H*" anyway, since it's
    just 'summing' a single value. I was thinking maybe the OP really meant
    to use "%C*"?
    fifo, May 26, 2004
    #6
  7. Fatted

    Anno Siegel Guest

    Fatted <> wrote in comp.lang.perl.misc:
    > Anno Siegel wrote:
    >
    > > fifo <> wrote in comp.lang.perl.misc:
    > >
    > >>Isn't this just the same as doing
    > >>
    > >> my $chksum = unpack("H*",$string);
    > >>
    > >>as unpack "H*" is only going to give you a single scalar anyway?

    > >
    > >
    > > We're not talking "H*" but "%H*". There's a *bug*, and it doesn't
    > > behave according to specification.
    > >
    > > Please read for comprehension.
    > >
    > > Anno

    >
    > I don't think I follow either :(
    >
    > take:
    >
    > my $string = 'ThisIsAString';
    > # PERFORM PLAIN UNPACK
    > my $chksum = unpack("H*",$string)."\n";
    > print $chksum."\n";
    >
    > gives:
    > 54686973497341537472696e67
    >
    > try:
    >
    > my $string = 'ThisIsAString';
    > # PERFORM CHECKSUM UNPACK
    > my $chksum = unpack("%H*",$string);
    > print $chksum."\n";
    >
    > gives:
    > 0
    > as discussed
    >
    > try suggested workaround:
    >
    > my $string = 'ThisIsAString';
    > # PERFORM WORKAROUND CHECKSUM UNPACK
    > my ($chksum) = unpack("%H*",$string);
    > print $chksum."\n";
    >
    > gives:
    > 54686973497341537472696e67
    > which is the same result as the plain unpack and not the checksum sought.


    Ugh, you're right. I didn't notice it doesn't do the checksum at all.
    Forget the workaround, sorry.

    Anno
    Anno Siegel, May 26, 2004
    #7
  8. Fatted

    Fatted Guest

    fifo wrote:

    > I agree that there's a bug with "%H*". The point I was trying to make
    > was that "%H*" doesn't do anything useful over "H*" anyway, since it's
    > just 'summing' a single value. I was thinking maybe the OP really meant
    > to use "%C*"?


    What I was looking for was the unpack equivalent of:
    ####
    my $string = 'ThisIsAString';
    my $chksum = 0;

    for( split(//,$string) )
    {
    $chksum += ord;
    }

    print sprintf("%X",$chksum)."\n";
    ####

    I thought "%H*" would handle that (if "H*" gives a concat of the hex
    values then "%H*" should give sum, right?), but then comparing "H*" with
    "C*":

    "H*" returns the concatentation of the hex values of the string
    whereas
    "C*" returns the decimal value of the first value.

    On the other hand "%C*" *does* return the checksum (in decimal).

    I've read and reread the perlfunc for pack and unpack and I'm now pretty
    confused.
    Fatted, May 26, 2004
    #8
  9. Fatted

    fifo Guest

    At 2004-05-26 15:41 +0200, Fatted wrote:
    > What I was looking for was the unpack equivalent of:
    > ####
    > my $string = 'ThisIsAString';
    > my $chksum = 0;
    >
    > for( split(//,$string) )
    > {
    > $chksum += ord;
    > }
    >
    > print sprintf("%X",$chksum)."\n";
    > ####
    >
    > I thought "%H*" would handle that (if "H*" gives a concat of the hex
    > values then "%H*" should give sum, right?), but then comparing "H*" with
    > "C*":
    >
    > "H*" returns the concatentation of the hex values of the string
    > whereas


    It returns a single string of hexadecimal digits.

    > "C*" returns the decimal value of the first value.


    No it returns a _list_ of the char values of each byte in the string:

    $ perl -le'print join ":", unpack "C*", "ThisIsAString"'
    84:104:105:115:73:115:65:83:116:114:105:110:103
    fifo, May 26, 2004
    #9
  10. Fatted

    Greg Bacon Guest

    In article <>,
    Fatted <> wrote:

    : What I was looking for was the unpack equivalent of:
    : ####
    : my $string = 'ThisIsAString';
    : my $chksum = 0;
    :
    : for( split(//,$string) )
    : {
    : $chksum += ord;
    : }
    :
    : print sprintf("%X",$chksum)."\n";
    : ####

    You're right there! Well, sort of. See below.

    $ cat try
    #!/usr/local/bin/perl -w

    use strict;
    use warnings;

    sub explicit_checksum {
    my $str = shift;

    my $sum = 0;
    $sum += ord for split // => $str;

    $sum;
    }

    sub unpack_checksum {
    unpack "%16C*", shift;
    }

    my $string = 'ThisIsAString';
    my $chksum = 0;

    for (split //, $string) {
    $chksum += ord;
    }

    my @method = (
    [ explicit => \&explicit_checksum ],
    [ unpack => \&unpack_checksum ],
    );

    for (@method) {
    my($name,$code) = @$_;

    printf "%-10s %X\n", $name . ":", $code->($string);
    }

    $ ./try
    explicit: 50C
    unpack: 50C

    These results match coincidentally. Given a long enough $string, i.e.,
    one whose ASCII values sum greater than 0xFFFF, only the least
    significant sixteen bits would match.

    For example:

    $ cat try
    [...]
    open my $fh, '/etc/lynx.cfg' or die "$0: open /etc/lynx.cfg: $!";
    my $string = join '', <$fh>;
    [...]

    $ ./try
    explicit: ADA3B4
    unpack: A3B4

    The unpack isn't equivalent, but that's because the checksum your code
    computes doesn't follow the convention of producing a result clamped
    to a certain number of bits, e.g., $sum & 0xFFFF for a 16-bit checksum.

    : I thought "%H*" would handle that (if "H*" gives a concat of the hex
    : values then "%H*" should give sum, right?), but then comparing "H*"
    : with "C*":

    Remember that H returns hex strings, but C returns unsigned char
    values. Which of these matches the values returned from Perl's ord
    operator?

    : On the other hand "%C*" *does* return the checksum (in decimal).

    No, it doesn't return a value in a particular base, just a number.
    Base is a representation, e.g., input and output, issue. Yes, I
    realize it's almost certainly a twos-complement bitpattern in some
    register in your machine, but we're speaking at the level of
    abstraction of the Perl programming language, not the bare metal.

    : I've read and reread the perlfunc for pack and unpack and I'm now
    : pretty confused.

    I hope this helps you through the confusion.

    Greg
    --
    'Necessity' is the plea for every infringement of human liberty. It is
    the argument of tyrants; it is the creed of slaves.
    -- William Pitt
    Greg Bacon, May 26, 2004
    #10
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Michael Fairbank

    class checksums

    Michael Fairbank, Dec 5, 2003, in forum: Java
    Replies:
    16
    Views:
    3,117
    Michael Fairbank
    Dec 12, 2003
  2. Chris

    How good are checksums?

    Chris, Apr 29, 2004, in forum: Java
    Replies:
    12
    Views:
    883
    Roedy Green
    Apr 30, 2004
  3. Igor Planinc

    Bit IO, digests, checksums

    Igor Planinc, Nov 15, 2005, in forum: Java
    Replies:
    15
    Views:
    664
    Andrey Kuznetsov
    Nov 18, 2005
  4. Fredrik Lundh

    Re: Calculating md5 checksums.

    Fredrik Lundh, Mar 3, 2006, in forum: Python
    Replies:
    1
    Views:
    337
    Nainto
    Mar 4, 2006
  5. Rob

    Files and Checksums

    Rob, Aug 27, 2003, in forum: Javascript
    Replies:
    0
    Views:
    71
Loading...

Share This Page