File Coverage

blib/lib/Mail/Exchange/CRC.pm
Criterion Covered Total %
statement 44 44 100.0
branch 7 8 87.5
condition n/a
subroutine 10 10 100.0
pod 4 4 100.0
total 65 66 98.4


line stmt bran cond sub pod time code
1             package Mail::Exchange::CRC;
2              
3             =head1 NAME
4             Mail::Exchange::CRC - implement the CRC algorithm used in RTF compression
5             and the named property to index PPS streams
6              
7             =head1 SYNOPSIS
8              
9             use Mail::Exchange::CRC;
10              
11             my $crc=Mail::Exchange::CRC::new();
12             while () {
13             $crc->append($_);
14             }
15             print $crc->value;
16              
17             print Mail::Exchange::CRC::crc($string);
18              
19             =head1 DESCRIPTION
20              
21             Mail::Exchange::CRC can be used in function mode or in object oriented mode.
22             In function mode, you pass a string and get back the crc immediately,
23             while in object mode, you initialize an object via C, then append data
24             to the object as needed, and fetch the resulting value at the end.
25              
26             The crc algorithm is documented in [MS-OXRTFCP], and happens to be the CRC-32
27             algorithm that is used in a lot of different places as well, for example
28             in the the IEEE 802.3 Ethernet CRC specification.
29              
30             =cut
31              
32 6     6   22551 use strict;
  6         12  
  6         255  
33 6     6   34 use warnings;
  6         15  
  6         205  
34 6     6   171 use 5.008;
  6         18  
  6         209  
35              
36 6     6   30 use Exporter;
  6         9  
  6         261  
37 6     6   32 use vars qw(@ISA @EXPORT_OK $VERSION);
  6         11  
  6         2884  
38              
39             @ISA=qw(Exporter);
40             @EXPORT_OK=qw(crc);
41             $VERSION = "0.02";
42              
43             our @crctable;
44             my $initialized;
45              
46             # taken from Image::Dot which uses the same values
47              
48             sub _make_crc_table {
49 1     1   2 my ($c, $n, $k);
50 1         5 for ($n = 0; $n < 256; $n++) {
51 256         235 $c = $n;
52 256         473 for ($k = 0; $k < 8; $k++) {
53 2048 100       2977 if ($c & 1) {
54 1024         2081 $c = 0xEDB88320 ^ ($c >> 1);
55             } else {
56 1024         1943 $c = $c >> 1;
57             }
58             }
59 256         578 $crctable[$n] = $c;
60             }
61             }
62              
63             =head2 new()
64              
65             $crc=Mail::Exchange::CRC::new([string]) - initialize a new CRC value
66              
67             Initialize a new CRC calculator, and calculate the CRC of C if
68             provided.
69              
70             =cut
71              
72             sub new {
73 4     4 1 511 my $class=shift;
74 4         5 my $string=shift;
75              
76 4 100       10 unless ($initialized) {
77 1         5 _make_crc_table();
78 1 50       7 die "internal error" unless $crctable[255] == 0x2D02EF8D;
79 1         3 $initialized=1;
80             }
81              
82 4         8 my $self={};
83 4         10 bless($self, $class);
84              
85 4         16 $self->{currval}=0;
86 4 100       8 if ($string) {
87 3         10 $self->append($string);
88             }
89 4         10 return $self;
90             }
91              
92             =head2 append()
93              
94             $crc->append(string)
95              
96             Appends another string to a CRC, calculating the CRC of the two strings
97             concatenated to each other
98              
99             The following are supposed to be equal:
100              
101             $crc1=Mail::Exchange::CRC::new("hello world");
102              
103              
104             $crc2=Mail::Exchange::CRC::new("hello");
105             $crc2->append(" world");
106             =cut
107              
108             sub append {
109 6     6 1 12 my $self=shift;
110 6         9 my $string=shift;
111              
112 6         18 foreach my $byte (unpack("C*", $string)) {
113 37         65 $self->{currval}=$crctable[($self->{currval} ^ $byte) & 0xff]
114             ^ ($self->{currval} >> 8);
115             }
116 6         15 return $self->{currval};
117             }
118              
119             =head2 value()
120              
121             $crcval=$crc->value()
122              
123             Returns the calculated value of the CRC.
124              
125             =cut
126              
127             sub value {
128 4     4 1 9 my $self=shift;
129 4         14 return $self->{currval};
130             }
131              
132             =head2 crc()
133              
134             $crc=Mail::Exchange::CRC::crc($string)
135              
136             Calculates the CRC of a string in an easy-to-use, non-object-oriented way.
137              
138             =cut
139              
140             sub crc {
141 1     1 1 216 my $string=shift;
142 1         9 return Mail::Exchange::CRC->new($string)->value;
143             }
144              
145             1;