132
|
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.io.digest.Crc32;
|
|
14
|
|
15 public import tango.io.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 if (value & 1) {
|
|
50 value &= 0xFFFFFFFE;
|
|
51 value /= 2;
|
|
52 value &= 0x7FFFFFFF;
|
|
53 value ^= polynomial;
|
|
54 }
|
|
55 else
|
|
56 {
|
|
57 value &= 0xFFFFFFFE;
|
|
58 value /= 2;
|
|
59 value &= 0x7FFFFFFF;
|
|
60 }
|
|
61 }
|
|
62 table[i] = value;
|
|
63 }
|
|
64 }
|
|
65
|
|
66 /** */
|
|
67 override void update (void[] input)
|
|
68 {
|
|
69 uint r = result; // DMD optimization
|
|
70 foreach (ubyte value; cast(ubyte[]) input)
|
|
71 {
|
|
72 auto i = cast(ubyte) r;// & 0xff;
|
|
73 i ^= value;
|
|
74 r &= 0xFFFFFF00;
|
|
75 r /= 0x100;
|
|
76 r &= 16777215;
|
|
77 r ^= table[i];
|
|
78 }
|
|
79 result = r;
|
|
80 }
|
|
81
|
|
82 /** The Crc32 digestSize is 4 */
|
|
83 override uint digestSize ()
|
|
84 {
|
|
85 return 4;
|
|
86 }
|
|
87
|
|
88 /** */
|
|
89 override ubyte[] binaryDigest(ubyte[] buf = null) {
|
|
90 if (buf.length < 4)
|
|
91 buf.length = 4;
|
|
92 uint v = ~result;
|
|
93 buf[3] = cast(ubyte) (v >> 24);
|
|
94 buf[2] = cast(ubyte) (v >> 16);
|
|
95 buf[1] = cast(ubyte) (v >> 8);
|
|
96 buf[0] = cast(ubyte) (v);
|
|
97 result = 0xffffffff;
|
|
98 return buf;
|
|
99 }
|
|
100
|
|
101 /** Returns the Crc32 digest as a uint */
|
|
102 uint crc32Digest() {
|
|
103 uint ret = ~result;
|
|
104 result = 0xffffffff;
|
|
105 return ret;
|
|
106 }
|
|
107 }
|
|
108
|
|
109 version (UnitTest)
|
|
110 {
|
|
111 unittest
|
|
112 {
|
|
113 scope c = new Crc32();
|
|
114 static ubyte[] data = [1,2,3,4,5,6,7,8,9,10];
|
|
115 c.update(data);
|
|
116 assert(c.binaryDigest() == cast(ubyte[]) x"7b572025");
|
|
117 c.update(data);
|
|
118 assert(c.crc32Digest == 0x2520577b);
|
|
119 c.update(data);
|
|
120 assert(c.hexDigest() == "7b572025");
|
|
121 }
|
|
122 }
|