File Coverage

blib/lib/Digest/CRC.pm
Criterion Covered Total %
statement 82 116 70.6
branch 15 28 53.5
condition 14 30 46.6
subroutine 22 37 59.4
pod 0 31 0.0
total 133 242 54.9


line stmt bran cond sub pod time code
1             package Digest::CRC;
2              
3 1     1   81648 use strict;
  1         3  
  1         39  
4 1     1   6 use vars qw($VERSION $XS_VERSION @ISA @EXPORT_OK %_typedef);
  1         2  
  1         2395  
5              
6             require Exporter;
7              
8             @ISA = qw(Exporter);
9              
10             @EXPORT_OK = qw(
11             crc8 crcsaej1850 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.23';
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             crcsaej1850 => [8,0xff,0xff,0,0x1D,0,0],
129             crcccitt => [16,0xffff,0,0,0x1021,0,0],
130             crc16 => [16,0,0,1,0x8005,1,0],
131             crcopenpgparmor => [24,0xB704CE,0,0,0x864CFB,0,0],
132             crc32 => [32,0xffffffff,0xffffffff,1,0x04C11DB7,1,0],
133             );
134              
135             sub new {
136 13     13 0 2267 my $that=shift;
137 13         41 my %params=@_;
138 13 50 66     70 die if defined($params{type}) && !exists($_typedef{$params{type}}) && $params{type} ne 'crc64';
      33        
139 13   33     43 my $class = ref($that) || $that;
140 13         77 my $self = {map { ($_ => $params{$_}) }
  104         240  
141             qw(type width init xorout refout poly refin cont)};
142 13         38 bless $self, $class;
143 13         34 $self->reset();
144 13 100       24 map { if (defined($params{$_})) { $self->{$_} = $params{$_} } }
  104         209  
  32         74  
145             qw(type width init xorout refout poly refin cont);
146 13         63 $self
147             }
148              
149             sub reset {
150 13     13 0 23 my $self = shift;
151 13         27 my $typeparams;
152             # default is crc32 if no type and no width is defined
153 13 100 100     54 if (!defined($self->{type}) && !defined($self->{width})) {
154 1         3 $self->{type} = "crc32";
155             }
156 13 100 66     114 if (defined($self->{type}) && exists($_typedef{$self->{type}})) {
157 10         27 $typeparams = $_typedef{$self->{type}};
158             $self->{width} = $typeparams->[0],
159             $self->{init} = $typeparams->[1],
160             $self->{xorout} = $typeparams->[2],
161             $self->{refout} = $typeparams->[3],
162             $self->{poly} = $typeparams->[4],
163             $self->{refin} = $typeparams->[5],
164 10         36 $self->{cont} = $typeparams->[6],
165             }
166 13 50       360 $self->{_tab} = defined($self->{width})?_tabinit($self->{width}, $self->{poly}, $self->{refin}):undef;
167 13         29 $self->{_data} = undef;
168 13         19 $self
169             }
170              
171             #########################################
172             # Private output converter functions:
173 10     10   194 sub _encode_hex { sprintf "%0${_[1]}x", $_[0] }
174              
175             sub _encode_base64 {
176 0     0   0 my ($res, $padding, $in) = ("", undef, $_[0]);
177 0         0 $in = pack("H*", sprintf("%x",$in));
178 0         0 while ($in =~ /(.{1,45})/gs) {
179 0         0 $res .= substr pack('u', $1), 1;
180 0         0 chop $res;
181             }
182 0         0 $res =~ tr|` -_|AA-Za-z0-9+/|;
183 0         0 $padding = (3 - length($in) % 3) % 3;
184 0 0       0 $res =~ s#.{$padding}$#'=' x $padding#e if $padding;
  0         0  
185 0         0 $res =~ s#(.{1,76})#$1\n#g;
186 0         0 $res
187             }
188              
189             #########################################
190             # OOP interface:
191              
192             sub add {
193 14     14 0 53 my $self = shift;
194 14 50       55 $self->{_data} .= join '', @_ if @_;
195 14         38 $self
196             }
197              
198             sub addfile {
199 2     2 0 78 my ($self,$fh) = @_;
200 2 50 33     35 if (!ref($fh) && ref(\$fh) ne "GLOB") {
201 2         799 require Symbol;
202 2         1032 $fh = Symbol::qualify($fh, scalar caller);
203             }
204 2         41 my $read = 0;
205 2         5 my $buffer = '';
206 2         4 my $crc;
207 2         3 my $oldinit = $self->{init};
208 2         53 while ($read = read $fh, $buffer, 32*1024) {
209 2         10 $self->add($buffer);
210 2         8 $crc = $self->digest;
211 2         3 $self->{cont}=1;
212 2         10 $self->{init}=$crc;
213             }
214 2         5 $self->{init} = $oldinit;
215 2         4 $self->{_crc} = $crc;
216 2 50       5 die __PACKAGE__, " read failed: $!" unless defined $read;
217 2         5 $self
218             }
219              
220       0 0   sub add_bits {
221             }
222              
223             sub digest {
224 16     16 0 57 my $self = shift;
225 16         19 my $crc;
226 16 100       35 if (!$self->{_crc}) {
227 14         26 my $init = $self->{init};
228 14 50 66     93 if (defined($self->{type}) && $self->{type} eq 'crc64' ||
      33        
      33        
229             defined($self->{width}) && $self->{width} eq 64) {
230 0         0 $crc = _crc64($self->{_data});
231             } else {
232             $crc =_crc($self->{_data},$self->{width},$init,$self->{xorout},
233 14         65 $self->{refin},$self->{refout},$self->{cont},$self->{_tab});
234             }
235             } else {
236 2         4 $crc = $self->{_crc};
237 2         4 $self->{_crc} = undef;
238             }
239 16         26 $self->{_data} = undef;
240 16         57 $crc
241             }
242              
243             sub hexdigest {
244 5     5 0 26 _encode_hex($_[0]->digest, $_[0]->{width}/4)
245             }
246              
247             sub b64digest {
248 0     0 0 0 _encode_base64($_[0]->digest)
249             }
250              
251             sub clone {
252 0     0 0 0 my $self = shift;
253             my $clone = {
254             type => $self->{type},
255             width => $self->{width},
256             init => $self->{init},
257             xorout => $self->{xorout},
258             poly => $self->{poly},
259             refin => $self->{refin},
260             refout => $self->{refout},
261             _data => $self->{_data},
262             cont => $self->{cont},
263             _tab => $self->{_tab}
264 0         0 };
265 0   0     0 bless $clone, ref $self || $self;
266             }
267              
268             #########################################
269             # Procedural interface:
270              
271             sub crc {
272 17     17 0 39 my ($message,$width,$init,$xorout,$refout,$poly,$refin,$cont) = @_;
273 17         588 _crc($message,$width,$init,$xorout,$refin,$refout,$cont,_tabinit($width,$poly,$refin));
274             }
275              
276             sub _cont {
277 15     15   45 my ($message,$init,@parameters) = @_;
278 15 50       44 if (defined $init) {
279 0         0 $parameters[1] = $init;
280 0         0 $parameters[6] = 1;
281             }
282 15         41 crc($message,@parameters);
283             }
284              
285             # CRC8
286             # poly: 07, width: 8, init: 00, revin: no, revout: no, xorout: no
287              
288 4     4 0 12 sub crc8 { _cont($_[0],$_[1],@{$_typedef{crc8}}) }
  4         13  
289              
290             # CRC-SAE-J1850 standard
291             # poly: 1D, width: 8, init: ff, refin: no, refout: no, xorout: FF
292              
293 1     1 0 3 sub crcsaej1850 { _cont($_[0],$_[1],@{$_typedef{crcsaej1850}}) }
  1         6  
294              
295             # CRC-CCITT standard
296             # poly: 1021, width: 16, init: ffff, refin: no, refout: no, xorout: no
297              
298 3     3 0 7 sub crcccitt { _cont($_[0],$_[1],@{$_typedef{crcccitt}}) }
  3         8  
299              
300             # CRC16
301             # poly: 8005, width: 16, init: 0000, revin: yes, revout: yes, xorout: no
302              
303 3     3 0 9 sub crc16 { _cont($_[0],$_[1],@{$_typedef{crc16}}) }
  3         10  
304              
305             # CRC-24 for OpenPGP ASCII Armor checksum
306             # https://tools.ietf.org/html/rfc4880#section-6
307             # poly: 0x864CFB, width: 24, init: 0xB704CE, refin: no, refout: no, xorout: no
308              
309 2     2 0 6 sub crcopenpgparmor { crc($_[0],@{$_typedef{crcopenpgparmor}}) }
  2         8  
310              
311             # CRC32
312             # poly: 04C11DB7, width: 32, init: FFFFFFFF, revin: yes, revout: yes,
313             # xorout: FFFFFFFF
314             # equivalent to: cksum -o3
315              
316 4     4 0 990 sub crc32 { _cont($_[0],$_[1],@{$_typedef{crc32}}) }
  4         19  
317              
318             # CRC64
319             # special XS implementation (_crc64)
320              
321 0 0   0 0 0 sub crc64 { _crc64($_[0],defined($_[1])?$_[1]:0) }
322              
323 0     0 0 0 sub crc_hex { _encode_hex(&crc,2) }
324              
325 0     0 0 0 sub crc_base64 { _encode_base64 &crc }
326              
327 1     1 0 4 sub crc8_hex { _encode_hex(&crc8,2) }
328              
329 0     0 0 0 sub crc8_base64 { _encode_base64 &crc8 }
330              
331 1     1 0 3 sub crcccitt_hex { _encode_hex(&crcccitt,4) }
332              
333 0     0 0 0 sub crcccitt_base64 { _encode_base64 &crcccitt }
334              
335 1     1 0 7 sub crc16_hex { _encode_hex(&crc16,4) }
336              
337 0     0 0 0 sub crc16_base64 { _encode_base64 &crc16 }
338              
339 1     1 0 3 sub crcopenpgparmor_hex { _encode_hex(&crcopenpgparmor,6) }
340              
341 0     0 0 0 sub crcopenpgparmor_base64 { _encode_base64 &crcopenpgparmor }
342              
343 1     1 0 1147 sub crc32_hex { _encode_hex(&crc32,8) }
344              
345 0     0 0   sub crc32_base64 { _encode_base64 &crc32 }
346              
347 0     0 0   sub crc64_hex { _encode_hex(&crc64,16) }
348              
349 0     0 0   sub crc64_base64 { _encode_base64 &crc64 }
350              
351             1;
352             __END__