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