diff --git a/CRC.xs b/CRC.xs new file mode 100644 index 0000000..f13f924 --- /dev/null +++ b/CRC.xs @@ -0,0 +1,199 @@ +#define PERL_NO_GET_CONTEXT +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" + +#ifndef NVTYPE +# if defined(USE_LONG_DOUBLE) && defined(HAS_LONG_DOUBLE) +# define NVTYPE long double +# else +# define NVTYPE double +# endif +typedef NVTYPE NV; +#endif + +#ifndef newSVuv +# define newSVuv(uv) (uv > ((~((UV)0))>>1) ? newSVnv((NV)uv) : newSViv((IV)uv)) +#endif + +#ifndef aTHX_ +# define aTHX_ +#endif + +#ifndef SvGETMAGIC +# define SvGETMAGIC(x) STMT_START { if (SvGMAGICAL(x)) mg_get(x); } STMT_END +#endif + +#define TABSIZE 256 + +static UV reflect(UV in, int width) +{ + int i; + UV out = 0; + + for (i = width; in && i; i--, in >>= 1) + out = (out << 1) | (in & 1); + + return out << i; +} + +MODULE = Digest::CRC PACKAGE = Digest::CRC + +PROTOTYPES: ENABLE + +UV +_reflect(in, width) + UV in + IV width + + CODE: + RETVAL = reflect(in, width); + + OUTPUT: + RETVAL + +SV * +_tabinit(width, poly, ref) + IV width + UV poly + IV ref + + PREINIT: + UV *tab; + UV mask, t, r, i; + int j, wm8; + + CODE: + if (ref) + poly = reflect(poly, width); + + mask = ((UV)1)<<(width-1); + mask = mask + (mask-1); + + i = TABSIZE*sizeof(UV); + RETVAL = newSV(i); + SvPOK_only(RETVAL); + SvCUR_set(RETVAL, i); + tab = (UV *) SvPVX(RETVAL); + + if (!ref) { + t = ((UV)1) << (width - 1); + wm8 = width - 8; + } + + for (i = 0; i < TABSIZE; i++) { + if (ref) { + r = i; + for (j = 0; j < 8; j++) + if (r & 1) + r = (r >> 1) ^ poly; + else + r >>= 1; + } + else { + r = i << (width - 8); + for (j = 0; j < 8; j++) + if (r & t) + r = (r << 1) ^ poly; + else + r <<= 1; + } + tab[i] = r & mask; + } + + OUTPUT: + RETVAL + +SV * +_crc(message, width, init, xorout, refin, refout, cont, table) + SV *message + IV width + UV init + UV xorout + IV refin + IV refout + IV cont + SV *table + + PREINIT: + UV crc, mask, *tab; + STRLEN len; + const char *msg, *end; + + CODE: + SvGETMAGIC(message); + + msg = SvPV(message, len); + end = msg + len; + mask = ((UV)1)<<(width-1); + mask = mask + (mask-1); + tab = (UV *) SvPVX(table); + + crc = refin ? reflect(init, width) : init; + if (cont) { + crc = (init ^ xorout) & mask; + if (refout ^ refin) + crc = reflect(crc, width); + } + + if (refin) { + while (msg < end) + crc = (crc >> 8) ^ tab[(crc ^ *msg++) & 0xFF]; + } + else { + int wm8 = width - 8; + while (msg < end) + crc = (crc << 8) ^ tab[((crc >> wm8) ^ *msg++) & 0xFF]; + } + + if (refout ^ refin) + crc = reflect(crc, width); + + crc = (crc ^ xorout) & mask; + + RETVAL = newSVuv(crc); + + OUTPUT: + RETVAL + +SV * +_crc64(message, crc=0) + SV * message + UV crc + + PREINIT: + unsigned long long poly64rev = 0xd800000000000000ULL; + unsigned long long part; + int i, j; + static int init = 0; + static unsigned long long CRCTable[256]; + STRLEN len; + const char *msg, *end; + + CODE: + SvGETMAGIC(message); + msg = SvPV(message, len); + end = msg + len; + + if (!init) { + init = 1; + + for (i = 0; i < 256; i++) { + part = i; + for (j = 0; j < 8; j++) { + if (part & 1) + part = (part >> 1) ^ poly64rev; + else + part >>= 1; + } + CRCTable[i] = part; + } + } + while (msg < end) + crc = CRCTable[(crc ^ *msg++) & 0xff] ^ (crc >> 8); + + RETVAL = newSVuv(crc); + + OUTPUT: + RETVAL + diff --git a/Changes b/Changes new file mode 100644 index 0000000..b179334 --- /dev/null +++ b/Changes @@ -0,0 +1,73 @@ +Revision history for Perl extension Digest::CRC. + +0.01 Wed Apr 21 15:12:59 2004 + - original version; created by h2xs 1.19 + +0.03 Fri Apr 23 10:57:39 2004 + - adopted to Digest:: + +0.04 Fri Apr 23 12:05:18 2004 + - added _hex functions + +0.05 Fri Apr 23 13:14:04 2004 + - some bug fixes + +0.06 Mon May 03 10:45:12 2004 + - two bug fixes from Tim Heaney + +0.07 Mon May 17 10:57:12 2004 + - crc8 bug fixed. Thanks to Mathis Moder + +0.08 Sat May 21 22:32:34 2004 + - crc8 bug fixed. Thanks to Mathis Moder + +0.09 Mon Jul 05 23:37:13 2004 + - major performance improvements by adding optional XS code. + Thanks to Marcus Holland-Moritz + +0.10 Sat Mar 18 21:07:22 2004 + - adapted behaviour to Digest + +0.11 Wed Oct 31 20:26:13 2007 + - fixed __reflect error + +0.12 Sat Nov 3 10:11:42 2007 + - Debug output removed + +0.13 Sun Nov 4 11:22:54 2007 + - fixed tests + +0.14 Mon Nov 5 08:10:11 2007 + - fixed __reflect error in non XS part + +0.15 Sun Sep 12 13:46:13 2010 + - added crc64 support, #50064 + Thanks to Anders Ossowicki + - added bit reversing per byte, #59575 + Thanks to Joel Peshkin + - clone method nwo copies content too + Thanks to Stefan Ochs + +0.16 Wed Sep 29 08:11:42 2010 + - fixed crc64 support for non-xs case, #61490, #61491 + +0.17 Sat Aug 27 13:59:31 2011 + - fixed non-xs code, #70535 + +0.18 Sat Nov 12 23:09:05 2011 + - added convenience wrappers for 'cont', #70672 + - fixed few issues in xs code, #70674 + - added openpgparmor support, #72387 + +0.19 Sun Feb 8 11:30:09 2015 + - fixed issue with OO crc64, #101999 + - remove Build.PL as it seems to have some issues with the XS support + +0.20 Sun Feb 8 16:45:13 2015 + - removed debug code + +0.21 Sat Feb 21 13:18:25 2015 + - new() throwing an error if an unsupported type is specified + +0.22 Sat Feb 18 17:45:31 2017 + - added padding for hex encoded digests diff --git a/MANIFEST b/MANIFEST new file mode 100644 index 0000000..33d6f05 --- /dev/null +++ b/MANIFEST @@ -0,0 +1,8 @@ +Changes +CRC.xs +MANIFEST +META.yml +Makefile.PL +README +lib/Digest/CRC.pm +t/crc.t diff --git a/META.yml b/META.yml new file mode 100644 index 0000000..4087944 --- /dev/null +++ b/META.yml @@ -0,0 +1,10 @@ +# http://module-build.sourceforge.net/META-spec.html +#XXXXXXX This is a prototype!!! It will change in the future!!! XXXXX# +name: Digest-CRC +version: 0.22 +version_from: lib/Digest/CRC.pm +installdirs: site +requires: + +distribution_type: module +generated_by: ExtUtils::MakeMaker version 6.17 diff --git a/Makefile.PL b/Makefile.PL new file mode 100644 index 0000000..4ea4d74 --- /dev/null +++ b/Makefile.PL @@ -0,0 +1,80 @@ +require 5.004; +use ExtUtils::MakeMaker; + +use Config qw(%Config); + +for (@ARGV) { + /^-pm/ and $no_xs = 1; + /^-xs/ and $no_xs = 0; +} + +sub init { + my $hash = $_[1]; + if ($no_xs) { + @{$hash}{XS,C} = ( {}, [] ); + } + $hash; +} + +sub write_makefile { + WriteMakefile( + NAME => 'Digest::CRC', + VERSION_FROM => 'lib/Digest/CRC.pm', # finds $VERSION + PL_FILES => {}, + CONFIGURE => \&init, + clean => {FILES => 'test.c typemap'} + ); +} + +sub no_cc { + $no_xs = 1; + print <<"EDQ"; + + I cannot determine if you have a C compiler + so I will install a perl-only implementation + + You can force installation of the XS version with + + perl Makefile.PL -xs + +EDQ + write_makefile(); + exit; +} + +if ($] < 5.006001) { + open(TYPEMAP,">typemap"); + print TYPEMAP <<'EOS'; +NV T_NV +UV T_UV + +INPUT +T_NV + $var = ($type)SvNV($arg) +T_UV + $var = ($type)SvUV($arg) + +OUTPUT +T_NV + sv_setnv($arg, (NV)$var); +T_UV + sv_setuv($arg, (UV)$var); + +EOS + close(TYPEMAP); +} + +write_makefile(); + +exit if defined $no_xs; + +print "Testing if you have a C compiler\n"; + +open(F,">test.c") or no_cc(); +print F <new(type=>"crc16"); + $ctx = Digest::CRC->new(width=>16, init=>0x0000, xorout=>0x0000, + poly=>0x8005, refin=>1, refout=>1); + $ctx->add($data); + $ctx->addfile(*FILE); + + $digest = $ctx->digest; + $digest = $ctx->hexdigest; + $digest = $ctx->b64digest; + +INSTALLATION + +To install this module type the following: + + perl Makefile.PL + make + make test + make install + +COPYRIGHT AND LICENCE + CRC algorithm code taken from "A PAINLESS GUIDE TO CRC ERROR DETECTION + ALGORITHMS". + + The author of this package disclaims all copyrights and releases it + into the public domain. diff --git a/lib/Digest/CRC.pm b/lib/Digest/CRC.pm new file mode 100644 index 0000000..dc2fd02 --- /dev/null +++ b/lib/Digest/CRC.pm @@ -0,0 +1,410 @@ +package Digest::CRC; + +use strict; +use vars qw($VERSION $XS_VERSION @ISA @EXPORT_OK %_typedef); + +require Exporter; + +@ISA = qw(Exporter); + +@EXPORT_OK = qw( + crc8 crcccitt crc16 crcopenpgparmor crc32 crc64 crc + crc_hex crc_base64 + crcccitt_hex crcccitt_base64 + crc8_hex crc8_base64 + crc16_hex crc16_base64 + crcopenpgparmor_hex crcopenpgparmor_base64 + crc32_hex crc32_base64 + crc64_hex crc64_base64 +); + +$VERSION = '0.22'; +$XS_VERSION = $VERSION; +#$VERSION = eval $VERSION; + +eval { + # PERL_DL_NONLAZY must be false, or any errors in loading will just + # cause the perl code to be tested + local $ENV{PERL_DL_NONLAZY} = 0 if $ENV{PERL_DL_NONLAZY}; + require DynaLoader; + local @ISA = qw(DynaLoader); + bootstrap Digest::CRC $XS_VERSION; + 1 +}; + +sub _reflectperl { + my ($in, $width) = @_; + my $out = 0; + for(my $i=1; $i < ($width+1); $i++) { + $out |= 1 << ($width-$i) if ($in & 1); + $in=$in>>1; + } + $out; +} + +# Only load the non-XS stuff on demand +defined &_crc or eval <<'ENOXS' or die $@; + +sub _reflect($$) { + my ($in, $width) = @_; + my $out = 0; + for(my $i=1; $i < ($width+1); $i++) { + $out |= 1 << ($width-$i) if ($in & 1); + $in=$in>>1; + } + $out; +} + +sub _tabinit($$$) { + my ($width,$poly_in,$ref) = @_; + my @crctab; + my $poly = $poly_in; + + if ($ref) { + $poly = _reflect($poly,$width); + } + + for (my $i=0; $i<256; $i++) { + my $r = $i<<($width-8); + $r = $i if $ref; + for (my $j=0; $j<8; $j++) { + if ($ref) { + $r = ($r>>1)^($r&1&&$poly) + } else { + if ($r&(1<<($width-1))) { + $r = ($r<<1)^$poly + } else { + $r = ($r<<1) + } + } + } + my $x=$r&2**$width-1; + push @crctab, $x; + } + \@crctab; +} + +sub _crc($$$$$$$$) { + my ($message,$width,$init,$xorout,$refin,$refout,$cont,$tab) = @_; + if ($cont) { + $init = ($init ^ $xorout); + $init = _reflect($init, $width) if $refin; + } + my $crc = $init; + if ($refin == 1) { + $crc = _reflect($crc,$width); + } elsif ($refin > 1 and $refin <= $width) { + $crc = _reflect($crc,$refin); + } + my $pos = -length $message; + my $mask = 2**$width-1; + while ($pos) { + if ($refin) { + $crc = ($crc>>8)^$tab->[($crc^ord(substr($message, $pos++, 1)))&0xff] + } else { + $crc = (($crc<<8))^$tab->[(($crc>>($width-8))^ord(substr $message,$pos++,1))&0xff] + } + } + + if ($refout && !$refin) { + if ($refout == 1) { + $crc = _reflect($crc,$width); + } elsif ($refout > 1 and $refout <= $width) { + $crc = _reflect($crc,$refout); + } + } + + $crc = $crc ^ $xorout; + $crc & $mask; +} + +1; + +ENOXS + +%_typedef = ( +# name, [width,init,xorout,refout,poly,refin,cont); + crc8 => [8,0,0,0,0x07,0,0], + crcccitt => [16,0xffff,0,0,0x1021,0,0], + crc16 => [16,0,0,1,0x8005,1,0], + crcopenpgparmor => [24,0xB704CE,0,0,0x864CFB,0,0], + crc32 => [32,0xffffffff,0xffffffff,1,0x04C11DB7,1,0], +); + +sub new { + my $that=shift; + my %params=@_; + die if defined($params{type}) && !exists($_typedef{$params{type}}) && $params{type} ne 'crc64'; + my $class = ref($that) || $that; + my $self = {map { ($_ => $params{$_}) } + qw(type width init xorout refout poly refin cont)}; + bless $self, $class; + $self->reset(); + map { if (defined($params{$_})) { $self->{$_} = $params{$_} } } + qw(type width init xorout refout poly refin cont); + $self +} + +sub reset { + my $self = shift; + my $typeparams; + # default is crc32 if no type and no width is defined + if (!defined($self->{type}) && !defined($self->{width})) { + $self->{type} = "crc32"; + } + if (defined($self->{type}) && exists($_typedef{$self->{type}})) { + $typeparams = $_typedef{$self->{type}}; + $self->{width} = $typeparams->[0], + $self->{init} = $typeparams->[1], + $self->{xorout} = $typeparams->[2], + $self->{refout} = $typeparams->[3], + $self->{poly} = $typeparams->[4], + $self->{refin} = $typeparams->[5], + $self->{cont} = $typeparams->[6], + } + $self->{_tab} = defined($self->{width})?_tabinit($self->{width}, $self->{poly}, $self->{refin}):undef; + $self->{_data} = undef; + $self +} + +######################################### +# Private output converter functions: +sub _encode_hex { sprintf "%0${_[1]}x", $_[0] } + +sub _encode_base64 { + my ($res, $padding, $in) = ("", undef, $_[0]); + $in = pack("H*", sprintf("%x",$in)); + while ($in =~ /(.{1,45})/gs) { + $res .= substr pack('u', $1), 1; + chop $res; + } + $res =~ tr|` -_|AA-Za-z0-9+/|; + $padding = (3 - length($in) % 3) % 3; + $res =~ s#.{$padding}$#'=' x $padding#e if $padding; + $res =~ s#(.{1,76})#$1\n#g; + $res +} + +######################################### +# OOP interface: + +sub add { + my $self = shift; + $self->{_data} .= join '', @_ if @_; + $self +} + +sub addfile { + my ($self,$fh) = @_; + if (!ref($fh) && ref(\$fh) ne "GLOB") { + require Symbol; + $fh = Symbol::qualify($fh, scalar caller); + } + my $read = 0; + my $buffer = ''; + my $crc; + my $oldinit = $self->{init}; + while ($read = read $fh, $buffer, 32*1024) { + $self->add($buffer); + $crc = $self->digest; + $self->{cont}=1; + $self->{init}=$crc; + } + $self->{init} = $oldinit; + $self->{_crc} = $crc; + die __PACKAGE__, " read failed: $!" unless defined $read; + $self +} + +sub add_bits { +} + +sub digest { + my $self = shift; + my $crc; + if (!$self->{_crc}) { + my $init = $self->{init}; + if (defined($self->{type}) && $self->{type} eq 'crc64' || + defined($self->{width}) && $self->{width} eq 64) { + $crc = _crc64($self->{_data}); + } else { + $crc =_crc($self->{_data},$self->{width},$init,$self->{xorout}, + $self->{refin},$self->{refout},$self->{cont},$self->{_tab}); + } + } else { + $crc = $self->{_crc}; + $self->{_crc} = undef; + } + $self->{_data} = undef; + $crc +} + +sub hexdigest { + _encode_hex($_[0]->digest, $_[0]->{width}/4) +} + +sub b64digest { + _encode_base64($_[0]->digest) +} + +sub clone { + my $self = shift; + my $clone = { + type => $self->{type}, + width => $self->{width}, + init => $self->{init}, + xorout => $self->{xorout}, + poly => $self->{poly}, + refin => $self->{refin}, + refout => $self->{refout}, + _data => $self->{_data}, + cont => $self->{cont}, + _tab => $self->{_tab} + }; + bless $clone, ref $self || $self; +} + +######################################### +# Procedural interface: + +sub crc { + my ($message,$width,$init,$xorout,$refout,$poly,$refin,$cont) = @_; + _crc($message,$width,$init,$xorout,$refin,$refout,$cont,_tabinit($width,$poly,$refin)); +} + +sub _cont { + my ($message,$init,@parameters) = @_; + if (defined $init) { + $parameters[1] = $init; + $parameters[6] = 1; + } + crc($message,@parameters); +} + +# CRC8 +# poly: 07, width: 8, init: 00, revin: no, revout: no, xorout: no + +sub crc8 { _cont($_[0],$_[1],@{$_typedef{crc8}}) } + +# CRC-CCITT standard +# poly: 1021, width: 16, init: ffff, refin: no, refout: no, xorout: no + +sub crcccitt { _cont($_[0],$_[1],@{$_typedef{crcccitt}}) } + +# CRC16 +# poly: 8005, width: 16, init: 0000, revin: yes, revout: yes, xorout: no + +sub crc16 { _cont($_[0],$_[1],@{$_typedef{crc16}}) } + +# CRC-24 for OpenPGP ASCII Armor checksum +# https://tools.ietf.org/html/rfc4880#section-6 +# poly: 0x864CFB, width: 24, init: 0xB704CE, refin: no, refout: no, xorout: no + +sub crcopenpgparmor { crc($_[0],@{$_typedef{crcopenpgparmor}}) } + +# CRC32 +# poly: 04C11DB7, width: 32, init: FFFFFFFF, revin: yes, revout: yes, +# xorout: FFFFFFFF +# equivalent to: cksum -o3 + +sub crc32 { _cont($_[0],$_[1],@{$_typedef{crc32}}) } + +# CRC64 +# special XS implementation (_crc64) + +sub crc64 { _crc64($_[0],defined($_[1])?$_[1]:0) } + +sub crc_hex { _encode_hex(&crc,2) } + +sub crc_base64 { _encode_base64 &crc } + +sub crc8_hex { _encode_hex(&crc8,2) } + +sub crc8_base64 { _encode_base64 &crc8 } + +sub crcccitt_hex { _encode_hex(&crcccitt,4) } + +sub crcccitt_base64 { _encode_base64 &crcccitt } + +sub crc16_hex { _encode_hex(&crc16,4) } + +sub crc16_base64 { _encode_base64 &crc16 } + +sub crcopenpgparmor_hex { _encode_hex(&crcopenpgparmor,6) } + +sub crcopenpgparmor_base64 { _encode_base64 &crcopenpgparmor } + +sub crc32_hex { _encode_hex(&crc32,8) } + +sub crc32_base64 { _encode_base64 &crc32 } + +sub crc64_hex { _encode_hex(&crc64,16) } + +sub crc64_base64 { _encode_base64 &crc64 } + +1; +__END__ + +=head1 NAME + +Digest::CRC - Generic CRC functions + +=head1 SYNOPSIS + + # Functional style + + use Digest::CRC qw(crc64 crc32 crc16 crcccitt crc crc8 crcopenpgparmor); + $crc = crc64("123456789"); + $crc = crc32("123456789"); + $crc = crc16("123456789"); + $crc = crcccitt("123456789"); + $crc = crc8("123456789"); + $crc = crcopenpgparmor("123456789"); + + $crc = crc($input,$width,$init,$xorout,$refout,$poly,$refin,$cont); + + + # add data to existing + + $crc = crc32("ABCD", $crc); + + + # OO style + use Digest::CRC; + + $ctx = Digest::CRC->new(type=>"crc16"); + $ctx = Digest::CRC->new(width=>16, init=>0x2345, xorout=>0x0000, + refout=>1, poly=>0x8005, refin=>1, cont=>1); + + $ctx->add($data); + $ctx->addfile(*FILE); + + $digest = $ctx->digest; + $digest = $ctx->hexdigest; + $digest = $ctx->b64digest; + + +=head1 DESCRIPTION + +The B module calculates CRC sums of all sorts. +It contains wrapper functions with the correct parameters for CRC-CCITT, +CRC-16, CRC-32 and CRC-64, as well as the CRC used in OpenPGP's +ASCII-armored checksum. + +=head1 SEE ALSO + +https://tools.ietf.org/html/rfc4880#section-6 + +=head1 AUTHOR + +Oliver Maul, oli@42.nu + +=head1 COPYRIGHT + +CRC algorithm code taken from "A PAINLESS GUIDE TO CRC ERROR DETECTION + ALGORITHMS". + +The author of this package disclaims all copyrights and +releases it into the public domain. + +=cut diff --git a/t/crc.t b/t/crc.t new file mode 100644 index 0000000..4a5b2f2 --- /dev/null +++ b/t/crc.t @@ -0,0 +1,137 @@ +BEGIN { + $tests = 31; + if ($ENV{'WITH_CRC64'}) { + $tests=$tests+2; + } + $| = 1; + + eval "use Test::More tests => $tests"; + + $@ and eval <<'ENDEV'; +$ok = 1; + +print "1..$tests\n"; + +sub ok { + my($res,$comment) = @_; + defined $comment and print "# $comment\n"; + $res or print "not "; + print "ok ", $ok++, "\n"; +} +ENDEV +} + +use Digest::CRC qw(crc64 crc32 crc16 crcccitt crc8 crcopenpgparmor + crc64_hex crc32_hex crc16_hex crcccitt_hex crc8_hex crcopenpgparmor_hex); +ok(1, 'use'); + +my $input = "123456789"; +my ($crc32,$crc16,$crcccitt,$crc8) = (crc32($input),crc16($input),crcccitt($input),crc8($input)); + +if ($ENV{'WITH_CRC64'}) { + my $crc64 = crc64($input); + ok($crc64 == 5090661014116757502, 'crc64 '.$crc64); + $ctx = Digest::CRC->new(type=>"crc64"); + $ctx->add($input); + $crc64 = $ctx->digest; + ok($crc64 == 5090661014116757502, 'OO crc64 '.$crc64); +} + +ok($crc32 == 3421780262, 'crc32'); +$crc32=$crc32^0xffffffff; +ok(crc32($input.join('', + map {chr(($crc32>>(8*$_))&0xff)} (0,1,2,3))) == 0xffffffff, + 'crc32 Nulltest'); +ok($crcccitt == 10673, 'crcccitt'); +ok($crc16 == 47933, 'crc16'); +ok($crc8 == 244, 'crc8'); +ok(($crc8=crc8($input.chr($crc8))) == 0, 'crc8 Nulltest'); +my $ctx; $ctx = Digest::CRC->new(); +$ctx->add($input); +ok($ctx->digest == 3421780262, 'OO crc32'); + +$crc32=$crc32^0xffffffff; + + +# addfile +open(F,"addfile(F); +close(F); +my $y = $ctx->digest; +ok($y == 4009136024, 'OO crc32 with addfile '.$y); + +# start at offset >0 with previous checksum result +$ctx = Digest::CRC->new(type=>"crc32",cont=>1,init=>460478609); +open(F,"addfile(F); +close(F); +$y = $ctx->digest; +ok($y == 2371909219, 'OO crc32 with init and addfile '.$y); + +$ctx = Digest::CRC->new(type=>"crcccitt"); +$ctx->add($input); +ok($ctx->digest == 10673, 'OO crcccitt'); + +$ctx = Digest::CRC->new(type=>"crc16"); +$ctx->add($input); +ok($ctx->digest == 47933, 'OO crc16'); + +$ctx = Digest::CRC->new(width=>16,init=>0,xorout=>0,refout=>1,poly=>0x3456, + refin=>1,cont=>0); +$ctx->add($input); +ok($ctx->digest == 12803, 'OO crc16 poly 3456'); + +$ctx = Digest::CRC->new(type=>"crc8"); +$ctx->add($input); +ok($ctx->digest == 244, 'OO crc8'); + +# crc8 test from Mathis Moder +$ctx = Digest::CRC->new(width=>8, init=>0xab, xorout=>0x00, refout=>0, poly=>0x07, + refin=>0, cont=>0); +$ctx->add($input); +ok($ctx->digest == 135, 'OO crc8 init=ab'); + +$ctx = Digest::CRC->new(width=>8, init=>0xab, xorout=>0xff, refout=>1, poly=>0x07, + refin=>1, cont=>0); +$ctx->add("f1"); +ok($ctx->digest == 106, 'OO crc8 init=ab, refout'); + +$input = join '', 'aa'..'zz'; +($crc32,$crc16,$crcccitt,$crc8) = (crc32($input),crc16($input),crcccitt($input),crc8($input)); + +# some more large messages +ok($crc32 == 0xCDA63E54, 'crc32'); +ok($crcccitt == 0x9702, 'crcccitt'); +ok($crc16 == 0x0220, 'crc16'); +ok($crc8 == 0x82, 'crc8'); + +# hex digest +my $hexinput = "ae"; +($crc32,$crc16,$crcccitt,$crc8,$crcopenpgparmor) = (crc32_hex($hexinput),crc16_hex($hexinput),crcccitt_hex($hexinput),crc8_hex($hexinput),crcopenpgparmor_hex($hexinput)); +ok($crc32 == "00e7ddce", 'crc32_hex'); # width padding to 4 bytes +ok($crcccitt == "1917", 'crcccitt_hex'); +ok($crc16 == "bbe9", 'crc16_hex'); +ok($crc8 == "dc", 'crc8_hex'); +ok($crcopenpgparmor == "3e653a", 'crcopenpgparmor_hex'); + +$ctx = Digest::CRC->new(type=>"crc8"); +$ctx->add($hexinput); +ok($ctx->hexdigest == "dc", 'OO crc8 hex'); +$ctx = Digest::CRC->new(type=>"crc16"); +$ctx->add($hexinput); +ok($ctx->hexdigest == "bbe9", 'OO crc16 hex'); +$ctx = Digest::CRC->new(type=>"crc32"); +$ctx->add($hexinput); +ok($ctx->hexdigest == "00e7ddce", 'OO crc32 hex'); +$ctx = Digest::CRC->new(type=>"crcccitt"); +$ctx->add($hexinput); +ok($ctx->hexdigest == "1917", 'OO crcccitt hex'); +$ctx = Digest::CRC->new(type=>"crcopenpgparmor"); +$ctx->add($hexinput); +ok($ctx->hexdigest == "3e653a", 'OO crcopenpgparmor hex'); + +# openpgparmor +my $openpgparmor = crcopenpgparmor($input); +ok($openpgparmor == 4874579, 'openpgparmor '.$openpgparmor);