File Coverage

blib/lib/Digest/CRC.pm
Criterion Covered Total %
statement 73 115 63.4
branch 15 28 53.5
condition 13 30 43.3
subroutine 14 36 38.8
pod 0 30 0.0
total 115 239 48.1


line stmt bran cond sub pod time code
1             package Digest::CRC;
2              
3 1     1   317177 use strict;
  1         4  
  1         122  
4 1     1   13 use vars qw($VERSION $XS_VERSION @ISA @EXPORT_OK %_typedef);
  1         4  
  1         2272  
5              
6             require Exporter;
7              
8             @ISA = qw(Exporter);
9              
10             @EXPORT_OK = qw(
11             crc8 crcccitt crc16 crcopenpgparmor crc32 crc64 crc
12             crc_hex crc_base64
13             crcccitt_hex crcccitt_base64
14             crc8_hex crc8_base64
15             crc16_hex crc16_base64
16             crcopenpgparmor_hex crcopenpgparmor_base64
17             crc32_hex crc32_base64
18             crc64_hex crc64_base64
19             );
20              
21             $VERSION = '0.21';
22             $XS_VERSION = $VERSION;
23             #$VERSION = eval $VERSION;
24              
25             eval {
26             # PERL_DL_NONLAZY must be false, or any errors in loading will just
27             # cause the perl code to be tested
28             local $ENV{PERL_DL_NONLAZY} = 0 if $ENV{PERL_DL_NONLAZY};
29             require DynaLoader;
30             local @ISA = qw(DynaLoader);
31             bootstrap Digest::CRC $XS_VERSION;
32             1
33             };
34              
35             sub _reflectperl {
36 0     0   0 my ($in, $width) = @_;
37 0         0 my $out = 0;
38 0         0 for(my $i=1; $i < ($width+1); $i++) {
39 0 0       0 $out |= 1 << ($width-$i) if ($in & 1);
40 0         0 $in=$in>>1;
41             }
42 0         0 $out;
43             }
44              
45             # Only load the non-XS stuff on demand
46             defined &_crc or eval <<'ENOXS' or die $@;
47              
48             sub _reflect($$) {
49             my ($in, $width) = @_;
50             my $out = 0;
51             for(my $i=1; $i < ($width+1); $i++) {
52             $out |= 1 << ($width-$i) if ($in & 1);
53             $in=$in>>1;
54             }
55             $out;
56             }
57              
58             sub _tabinit($$$) {
59             my ($width,$poly_in,$ref) = @_;
60             my @crctab;
61             my $poly = $poly_in;
62              
63             if ($ref) {
64             $poly = _reflect($poly,$width);
65             }
66              
67             for (my $i=0; $i<256; $i++) {
68             my $r = $i<<($width-8);
69             $r = $i if $ref;
70             for (my $j=0; $j<8; $j++) {
71             if ($ref) {
72             $r = ($r>>1)^($r&1&&$poly)
73             } else {
74             if ($r&(1<<($width-1))) {
75             $r = ($r<<1)^$poly
76             } else {
77             $r = ($r<<1)
78             }
79             }
80             }
81             my $x=$r&2**$width-1;
82             push @crctab, $x;
83             }
84             \@crctab;
85             }
86              
87             sub _crc($$$$$$$$) {
88             my ($message,$width,$init,$xorout,$refin,$refout,$cont,$tab) = @_;
89             if ($cont) {
90             $init = ($init ^ $xorout);
91             $init = _reflect($init, $width) if $refin;
92             }
93             my $crc = $init;
94             if ($refin == 1) {
95             $crc = _reflect($crc,$width);
96             } elsif ($refin > 1 and $refin <= $width) {
97             $crc = _reflect($crc,$refin);
98             }
99             my $pos = -length $message;
100             my $mask = 2**$width-1;
101             while ($pos) {
102             if ($refin) {
103             $crc = ($crc>>8)^$tab->[($crc^ord(substr($message, $pos++, 1)))&0xff]
104             } else {
105             $crc = (($crc<<8))^$tab->[(($crc>>($width-8))^ord(substr $message,$pos++,1))&0xff]
106             }
107             }
108              
109             if ($refout && !$refin) {
110             if ($refout == 1) {
111             $crc = _reflect($crc,$width);
112             } elsif ($refout > 1 and $refout <= $width) {
113             $crc = _reflect($crc,$refout);
114             }
115             }
116              
117             $crc = $crc ^ $xorout;
118             $crc & $mask;
119             }
120              
121             1;
122              
123             ENOXS
124              
125             %_typedef = (
126             # name, [width,init,xorout,refout,poly,refin,cont);
127             crc8 => [8,0,0,0,0x07,0,0],
128             crcccitt => [16,0xffff,0,0,0x1021,0,0],
129             crc16 => [16,0,0,1,0x8005,1,0],
130             crcopenpgparmor => [24,0xB704CE,0,0,0x864CFB,0,0],
131             crc32 => [32,0xffffffff,0xffffffff,1,0x04C11DB7,1,0],
132             );
133              
134             sub new {
135 8     8 0 978 my $that=shift;
136 8         30 my %params=@_;
137 8 50 66     47 die if defined($params{type}) && !exists($_typedef{$params{type}}) && $params{type} ne 'crc64';
      33        
138 8   33     36 my $class = ref($that) || $that;
139 8         15 my $self = {map { ($_ => $params{$_}) }
  64         139  
140             qw(type width init xorout refout poly refin cont)};
141 8         34 bless $self, $class;
142 8         21 $self->reset();
143 8 100       17 map { if (defined($params{$_})) { $self->{$_} = $params{$_} } }
  64         154  
  27         84  
144             qw(type width init xorout refout poly refin cont);
145 8         28 $self
146             }
147              
148             sub reset {
149 8     8 0 12 my $self = shift;
150 8         9 my $typeparams;
151             # default is crc32 if no type and no width is defined
152 8 100 66     52 if (!defined($self->{type}) && !defined($self->{width})) {
153 1         4 $self->{type} = "crc32";
154             }
155 8 100 66     44 if (defined($self->{type}) && exists($_typedef{$self->{type}})) {
156 5         11 $typeparams = $_typedef{$self->{type}};
157 5         24 $self->{width} = $typeparams->[0],
158             $self->{init} = $typeparams->[1],
159             $self->{xorout} = $typeparams->[2],
160             $self->{refout} = $typeparams->[3],
161             $self->{poly} = $typeparams->[4],
162             $self->{refin} = $typeparams->[5],
163             $self->{cont} = $typeparams->[6],
164             }
165 8 50       739 $self->{_tab} = defined($self->{width})?_tabinit($self->{width}, $self->{poly}, $self->{refin}):undef;
166 8         16 $self->{_data} = undef;
167 8         13 $self
168             }
169              
170             #########################################
171             # Private output converter functions:
172 0     0   0 sub _encode_hex { sprintf "%x", $_[0] }
173              
174             sub _encode_base64 {
175 0     0   0 my ($res, $padding, $in) = ("", undef, $_[0]);
176 0         0 $in = pack("H*", sprintf("%x",$in));
177 0         0 while ($in =~ /(.{1,45})/gs) {
178 0         0 $res .= substr pack('u', $1), 1;
179 0         0 chop $res;
180             }
181 0         0 $res =~ tr|` -_|AA-Za-z0-9+/|;
182 0         0 $padding = (3 - length($in) % 3) % 3;
183 0 0       0 $res =~ s#.{$padding}$#'=' x $padding#e if $padding;
  0         0  
184 0         0 $res =~ s#(.{1,76})#$1\n#g;
185 0         0 $res
186             }
187              
188             #########################################
189             # OOP interface:
190              
191             sub add {
192 9     9 0 41 my $self = shift;
193 9 50       41 $self->{_data} .= join '', @_ if @_;
194 9         14 $self
195             }
196              
197             sub addfile {
198 2     2 0 52 my ($self,$fh) = @_;
199 2 50 33     17 if (!ref($fh) && ref(\$fh) ne "GLOB") {
200 2         769 require Symbol;
201 2         1060 $fh = Symbol::qualify($fh, scalar caller);
202             }
203 2         33 my $read = 0;
204 2         3 my $buffer = '';
205 2         4 my $crc;
206 2         3 my $oldinit = $self->{init};
207 2         49 while ($read = read $fh, $buffer, 32*1024) {
208 2         8 $self->add($buffer);
209 2         5 $crc = $self->digest;
210 2         4 $self->{cont}=1;
211 2         10 $self->{init}=$crc;
212             }
213 2         4 $self->{init} = $oldinit;
214 2         4 $self->{_crc} = $crc;
215 2 50       6 die __PACKAGE__, " read failed: $!" unless defined $read;
216 2         6 $self
217             }
218              
219 0     0 0 0 sub add_bits {
220             }
221              
222             sub digest {
223 11     11 0 38 my $self = shift;
224 11         12 my $crc;
225 11 100       25 if (!$self->{_crc}) {
226 9         12 my $init = $self->{init};
227 9 50 66     92 if (defined($self->{type}) && $self->{type} eq 'crc64' ||
      33        
      33        
228             defined($self->{width}) && $self->{width} eq 64) {
229 0         0 $crc = _crc64($self->{_data});
230             } else {
231 9         52 $crc =_crc($self->{_data},$self->{width},$init,$self->{xorout},
232             $self->{refin},$self->{refout},$self->{cont},$self->{_tab});
233             }
234             } else {
235 2         3 $crc = $self->{_crc};
236 2         3 $self->{_crc} = undef;
237             }
238 11         20 $self->{_data} = undef;
239 11         58 $crc
240             }
241              
242             sub hexdigest {
243 0     0 0 0 _encode_hex($_[0]->digest)
244             }
245              
246             sub b64digest {
247 0     0 0 0 _encode_base64($_[0]->digest)
248             }
249              
250             sub clone {
251 0     0 0 0 my $self = shift;
252 0         0 my $clone = {
253             type => $self->{type},
254             width => $self->{width},
255             init => $self->{init},
256             xorout => $self->{xorout},
257             poly => $self->{poly},
258             refin => $self->{refin},
259             refout => $self->{refout},
260             _data => $self->{_data},
261             cont => $self->{cont},
262             _tab => $self->{_tab}
263             };
264 0   0     0 bless $clone, ref $self || $self;
265             }
266              
267             #########################################
268             # Procedural interface:
269              
270             sub crc {
271 11     11 0 18 my ($message,$width,$init,$xorout,$refout,$poly,$refin,$cont) = @_;
272 11         395 _crc($message,$width,$init,$xorout,$refin,$refout,$cont,_tabinit($width,$poly,$refin));
273             }
274              
275             sub _cont {
276 10     10   32 my ($message,$init,@parameters) = @_;
277 10 50       24 if (defined $init) {
278 0         0 $parameters[1] = $init;
279 0         0 $parameters[6] = 1;
280             }
281 10         22 crc($message,@parameters);
282             }
283              
284             # CRC8
285             # poly: 07, width: 8, init: 00, revin: no, revout: no, xorout: no
286              
287 3     3 0 10 sub crc8 { _cont($_[0],$_[1],@{$_typedef{crc8}}) }
  3         9  
288              
289             # CRC-CCITT standard
290             # poly: 1021, width: 16, init: ffff, refin: no, refout: no, xorout: no
291              
292 2     2 0 5 sub crcccitt { _cont($_[0],$_[1],@{$_typedef{crcccitt}}) }
  2         7  
293              
294             # CRC16
295             # poly: 8005, width: 16, init: 0000, revin: yes, revout: yes, xorout: no
296              
297 2     2 0 7 sub crc16 { _cont($_[0],$_[1],@{$_typedef{crc16}}) }
  2         8  
298              
299             # CRC-24 for OpenPGP ASCII Armor checksum
300             # https://tools.ietf.org/html/rfc4880#section-6
301             # poly: 0x864CFB, width: 24, init: 0xB704CE, refin: no, refout: no, xorout: no
302              
303 1     1 0 1751 sub crcopenpgparmor { crc($_[0],@{$_typedef{crcopenpgparmor}}) }
  1         5  
304              
305             # CRC32
306             # poly: 04C11DB7, width: 32, init: FFFFFFFF, revin: yes, revout: yes,
307             # xorout: FFFFFFFF
308             # equivalent to: cksum -o3
309              
310 3     3 0 1340 sub crc32 { _cont($_[0],$_[1],@{$_typedef{crc32}}) }
  3         15  
311              
312             # CRC64
313             # special XS implementation (_crc64)
314              
315 0 0   0 0   sub crc64 { _crc64($_[0],defined($_[1])?$_[1]:0) }
316              
317 0     0 0   sub crc_hex { _encode_hex &crc }
318              
319 0     0 0   sub crc_base64 { _encode_base64 &crc }
320              
321 0     0 0   sub crc8_hex { _encode_hex &crc8 }
322              
323 0     0 0   sub crc8_base64 { _encode_base64 &crc8 }
324              
325 0     0 0   sub crcccitt_hex { _encode_hex &crcccitt }
326              
327 0     0 0   sub crcccitt_base64 { _encode_base64 &crcccitt }
328              
329 0     0 0   sub crc16_hex { _encode_hex &crc16 }
330              
331 0     0 0   sub crc16_base64 { _encode_base64 &crc16 }
332              
333 0     0 0   sub crcopenpgparmor_hex { _encode_hex &crcopenpgparmor }
334              
335 0     0 0   sub crcopenpgparmor_base64 { _encode_base64 &crcopenpgparmor }
336              
337 0     0 0   sub crc32_hex { _encode_hex &crc32 }
338              
339 0     0 0   sub crc32_base64 { _encode_base64 &crc32 }
340              
341 0     0 0   sub crc64_hex { _encode_hex &crc64 }
342              
343 0     0 0   sub crc64_base64 { _encode_base64 &crc64 }
344              
345             1;
346             __END__