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   58191 use strict;
  1         3  
  1         30  
4 1     1   4 use vars qw($VERSION $XS_VERSION @ISA @EXPORT_OK %_typedef);
  1         2  
  1         2077  
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.24';
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 1766 my $that=shift;
137 13         32 my %params=@_;
138 13 50 66     54 die if defined($params{type}) && !exists($_typedef{$params{type}}) && $params{type} ne 'crc64';
      33        
139 13   33     34 my $class = ref($that) || $that;
140 13         42 my $self = {map { ($_ => $params{$_}) }
  104         179  
141             qw(type width init xorout refout poly refin cont)};
142 13         27 bless $self, $class;
143 13         25 $self->reset();
144 13 100       17 map { if (defined($params{$_})) { $self->{$_} = $params{$_} } }
  104         176  
  32         56  
145             qw(type width init xorout refout poly refin cont);
146 13         49 $self
147             }
148              
149             sub reset {
150 13     13 0 16 my $self = shift;
151 13         18 my $typeparams;
152             # default is crc32 if no type and no width is defined
153 13 100 100     36 if (!defined($self->{type}) && !defined($self->{width})) {
154 1         2 $self->{type} = "crc32";
155             }
156 13 100 66     43 if (defined($self->{type}) && exists($_typedef{$self->{type}})) {
157 10         19 $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         24 $self->{cont} = $typeparams->[6],
165             }
166 13 50       292 $self->{_tab} = defined($self->{width})?_tabinit($self->{width}, $self->{poly}, $self->{refin}):undef;
167 13         21 $self->{_data} = undef;
168 13         17 $self
169             }
170              
171             #########################################
172             # Private output converter functions:
173 10     10   129 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 37 my $self = shift;
194 14 50       48 $self->{_data} .= join '', @_ if @_;
195 14         20 $self
196             }
197              
198             sub addfile {
199 2     2 0 48 my ($self,$fh) = @_;
200 2 50 33     11 if (!ref($fh) && ref(\$fh) ne "GLOB") {
201 2         506 require Symbol;
202 2         703 $fh = Symbol::qualify($fh, scalar caller);
203             }
204 2         31 my $read = 0;
205 2         4 my $buffer = '';
206 2         3 my $crc;
207 2         3 my $oldinit = $self->{init};
208 2         60 while ($read = read $fh, $buffer, 32*1024) {
209 2         8 $self->add($buffer);
210 2         5 $crc = $self->digest;
211 2         4 $self->{cont}=1;
212 2         8 $self->{init}=$crc;
213             }
214 2         4 $self->{init} = $oldinit;
215 2         3 $self->{_crc} = $crc;
216 2 50       4 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 45 my $self = shift;
225 16         25 my $crc;
226 16 100       30 if (!$self->{_crc}) {
227 14         15 my $init = $self->{init};
228 14 50 66     70 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         56 $self->{refin},$self->{refout},$self->{cont},$self->{_tab});
234             }
235             } else {
236 2         2 $crc = $self->{_crc};
237 2         4 $self->{_crc} = undef;
238             }
239 16         19 $self->{_data} = undef;
240 16         45 $crc
241             }
242              
243             sub hexdigest {
244 5     5 0 18 _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             _crc => $self->{_crc}
265 0         0 };
266 0   0     0 bless $clone, ref $self || $self;
267             }
268              
269             #########################################
270             # Procedural interface:
271              
272             sub crc {
273 17     17 0 27 my ($message,$width,$init,$xorout,$refout,$poly,$refin,$cont) = @_;
274 17         442 _crc($message,$width,$init,$xorout,$refin,$refout,$cont,_tabinit($width,$poly,$refin));
275             }
276              
277             sub _cont {
278 15     15   37 my ($message,$init,@parameters) = @_;
279 15 50       30 if (defined $init) {
280 0         0 $parameters[1] = $init;
281 0         0 $parameters[6] = 1;
282             }
283 15         24 crc($message,@parameters);
284             }
285              
286             # CRC8
287             # poly: 07, width: 8, init: 00, revin: no, revout: no, xorout: no
288              
289 4     4 0 10 sub crc8 { _cont($_[0],$_[1],@{$_typedef{crc8}}) }
  4         9  
290              
291             # CRC-SAE-J1850 standard
292             # poly: 1D, width: 8, init: ff, refin: no, refout: no, xorout: FF
293              
294 1     1 0 2 sub crcsaej1850 { _cont($_[0],$_[1],@{$_typedef{crcsaej1850}}) }
  1         5  
295              
296             # CRC-CCITT standard
297             # poly: 1021, width: 16, init: ffff, refin: no, refout: no, xorout: no
298              
299 3     3 0 7 sub crcccitt { _cont($_[0],$_[1],@{$_typedef{crcccitt}}) }
  3         8  
300              
301             # CRC16
302             # poly: 8005, width: 16, init: 0000, revin: yes, revout: yes, xorout: no
303              
304 3     3 0 7 sub crc16 { _cont($_[0],$_[1],@{$_typedef{crc16}}) }
  3         7  
305              
306             # CRC-24 for OpenPGP ASCII Armor checksum
307             # https://tools.ietf.org/html/rfc4880#section-6
308             # poly: 0x864CFB, width: 24, init: 0xB704CE, refin: no, refout: no, xorout: no
309              
310 2     2 0 5 sub crcopenpgparmor { crc($_[0],@{$_typedef{crcopenpgparmor}}) }
  2         7  
311              
312             # CRC32
313             # poly: 04C11DB7, width: 32, init: FFFFFFFF, revin: yes, revout: yes,
314             # xorout: FFFFFFFF
315             # equivalent to: cksum -o3
316              
317 4     4 0 781 sub crc32 { _cont($_[0],$_[1],@{$_typedef{crc32}}) }
  4         15  
318              
319             # CRC64
320             # special XS implementation (_crc64)
321              
322 0 0   0 0 0 sub crc64 { _crc64($_[0],defined($_[1])?$_[1]:0) }
323              
324 0     0 0 0 sub crc_hex { _encode_hex(&crc,2) }
325              
326 0     0 0 0 sub crc_base64 { _encode_base64 &crc }
327              
328 1     1 0 2 sub crc8_hex { _encode_hex(&crc8,2) }
329              
330 0     0 0 0 sub crc8_base64 { _encode_base64 &crc8 }
331              
332 1     1 0 5 sub crcccitt_hex { _encode_hex(&crcccitt,4) }
333              
334 0     0 0 0 sub crcccitt_base64 { _encode_base64 &crcccitt }
335              
336 1     1 0 3 sub crc16_hex { _encode_hex(&crc16,4) }
337              
338 0     0 0 0 sub crc16_base64 { _encode_base64 &crc16 }
339              
340 1     1 0 3 sub crcopenpgparmor_hex { _encode_hex(&crcopenpgparmor,6) }
341              
342 0     0 0 0 sub crcopenpgparmor_base64 { _encode_base64 &crcopenpgparmor }
343              
344 1     1 0 881 sub crc32_hex { _encode_hex(&crc32,8) }
345              
346 0     0 0   sub crc32_base64 { _encode_base64 &crc32 }
347              
348 0     0 0   sub crc64_hex { _encode_hex(&crc64,16) }
349              
350 0     0 0   sub crc64_base64 { _encode_base64 &crc64 }
351              
352             1;
353             __END__