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 }