Perl-only CRC32 function (without C code)
It may look like a stupid idea, since the CRC32 has been implemented in some Perl modules which can be downloaded from CPAN. But all functions I found involve an XS part, which essentially means that a compilation of C code has to take place during the installation.
In other words, these modules can’t be just attached to a bundle of Perl code, but they have to be installed on a machine where it’s permitted. Or at least, compilation capabilities are necessary. Which can turn into a mess if the target is a Windows-running computer barely having Perl installed.
So I adapted one of the implementations of the mostly used CRC32 calculation, and wrote it in pure Perl. It’s really not the efficient way to obtain a CRC, and I wouldn’t try it on long sequences. Its advantage is also its disadvantage: It’s all in Perl.
Before giving the function away, I’d just point out that if one tries the following snippet
#!/usr/bin/perl use warnings; use strict; require String::CRC32; require Digest::CRC; my $str = "This is just any string."; my $refcrc = String::CRC32::crc32($str); my $refcrc2 = Digest::CRC::crc32($str); my $mycrc = mycrc32($str);
then $refcrc, $refcrc2 and $mycrc will have the same value (the last of which is calculated by the function at the end of this post).
And if we’re at it, I’d also point out that for any string $str, the following code
my $append = mycrc32($str) ^ 0xffffffff; my $res = mycrc32($str.pack("V", $append));
yields a CRC in $res which equals Oxffffffff. This is a well-known trick with CRCs: Append the CRC to the string for which it was calculated, and get a fixed value. And by they way, the CRC is done in Little Endian setting, so the parallel Linux kernel operation would be crc32_le(~0, string, len), only that crc32_le returns the value XORed by Oxffffffff (or is it the Perl version being upside down? I don’t know). Also note that the initial value of the CRC is set to ~0, which is effectively Oxffffffff again.
OK, time to show the function. It’s released to the public domain (Creative Commons’ CC0, if you like), so feel free to make any use of it.
sub mycrc32 { my ($input, $init_value, $polynomial) = @_; $init_value = 0 unless (defined $init_value); $polynomial = 0xedb88320 unless (defined $polynomial); my @lookup_table; for (my $i=0; $i<256; $i++) { my $x = $i; for (my $j=0; $j<8; $j++) { if ($x & 1) { $x = ($x >> 1) ^ $polynomial; } else { $x = $x >> 1; } } push @lookup_table, $x; } my $crc = $init_value ^ 0xffffffff; foreach my $x (unpack ('C*', $input)) { $crc = (($crc >> 8) & 0xffffff) ^ $lookup_table[ ($crc ^ $x) & 0xff ]; } $crc = $crc ^ 0xffffffff; return $crc; }
Reader Comments
Thanks!!!
Works perfectly, thank you.
Thank you, this works perfectly!
Works great, very concise – thanks!
Thanks. Could you add a crc64 version please? :)