1 /*******************************************************************************
2 
3         copyright:      Copyright (c) 2006 James Pelcis. All rights reserved
4 
5         license:        BSD style: $(LICENSE)
6 
7         version:        Initial release: August 2006
8 
9         author:         James Pelcis
10 
11 *******************************************************************************/
12 
13 module tango.util.digest.Crc32;
14 
15 public import tango.util.digest.Digest;
16 
17 
18 /** This class implements the CRC-32 checksum algorithm.
19     The digest returned is a little-endian 4 byte string. */
20 final class Crc32 : Digest
21 {
22         private uint[256] table;
23         private uint result = 0xffffffff;
24 
25         /**
26          * Create a cloned CRC32
27          */
28         this (Crc32 crc32)
29         {
30                 this.table[] = crc32.table[];
31                 this.result = crc32.result;
32         }
33 
34         /**
35          * Prepare Crc32 to checksum the data with a given polynomial.
36          *
37          * Params:
38          *      polynomial = The magic CRC number to base calculations on.  The
39          *      default compatible with ZIP, PNG, ethernet and others. Note: This
40          *      default value has poor error correcting properties.
41          */
42         this (uint polynomial = 0xEDB88320U)
43         {
44                 for (int i = 0; i < 256; i++)
45                 {
46                         uint value = i;
47                         for (int j = 8; j > 0; j--)
48                         {
49                                 version (Gim)
50                                 {
51                                 if (value & 1) 
52                                    {
53                                    value >>>= 1;
54                                    value ^= polynomial;
55                                    }
56                                 else
57                                    value >>>= 1;
58                                 }
59                                 else
60                                 {
61                                 if (value & 1) {
62                                         value &= 0xFFFFFFFE;
63                                         value /= 2;
64                                         value &= 0x7FFFFFFF;
65                                         value ^= polynomial;
66                                 }
67                                 else
68                                 {
69                                         value &= 0xFFFFFFFE;
70                                         value /= 2;
71                                         value &= 0x7FFFFFFF;
72                                 }
73                                 }
74                         }
75                         table[i] = value;
76                 }
77         }
78 
79         /** */
80         override Crc32 update (const(void[]) input)
81         {
82                 uint r = result; // DMD optimization
83                 foreach (ubyte value; cast(const(ubyte[])) input)
84                 {
85                         auto i = cast(ubyte) r;// & 0xff;
86                         i ^= value;
87                         version (Gim)
88                         {
89                         r >>>= 8;
90                         }
91                         else
92                         {
93                         r &= 0xFFFFFF00;
94                         r /= 0x100;
95                         r &= 16777215;
96                         }
97                         r ^= table[i];
98                 }
99                 result = r;
100                 return this;
101         }
102 
103         /** The Crc32 digestSize is 4 */
104         override uint digestSize ()
105         {
106                 return 4;
107         }
108 
109         /** */
110         override ubyte[] binaryDigest(ubyte[] buf = null) {
111                 if (buf.length < 4)
112                         buf.length = 4;
113                 uint v = ~result;
114                 buf[3] = cast(ubyte) (v >> 24);
115                 buf[2] = cast(ubyte) (v >> 16);
116                 buf[1] = cast(ubyte) (v >> 8);
117                 buf[0] = cast(ubyte) (v);
118                 result = 0xffffffff;
119                 return buf;
120         }
121 
122         /** Returns the Crc32 digest as a uint */
123         uint crc32Digest() {
124                 uint ret = ~result;
125                 result = 0xffffffff;
126                 return ret;
127         }
128 }
129 
130 debug(UnitTest)
131 {
132         unittest 
133         {
134         scope c = new Crc32();
135         static ubyte[] data = [1,2,3,4,5,6,7,8,9,10];
136         c.update(data);
137         assert(c.binaryDigest() == cast(ubyte[]) x"7b572025".dup);
138         c.update(data);
139         assert(c.crc32Digest() == 0x2520577b);
140         c.update(data);
141         assert(c.hexDigest() == "7b572025".dup);
142         }
143 }