| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 | /******************************************************************************* copyright: Copyright (c) 2006 James Pelcis. All rights reserved license: BSD style: $(LICENSE) version: Initial release: August 2006 author: James Pelcis *******************************************************************************/ module tango.util.digest.Crc32; public import tango.util.digest.Digest; /** This class implements the CRC-32 checksum algorithm. The digest returned is a little-endian 4 byte string. */ final class Crc32 : Digest { private uint[256] table; private uint result = 0xffffffff; /** * Create a cloned CRC32 */ this (Crc32 crc32) { this.table[] = crc32.table[]; this.result = crc32.result; } /** * Prepare Crc32 to checksum the data with a given polynomial. * * Params: * polynomial = The magic CRC number to base calculations on. The * default compatible with ZIP, PNG, ethernet and others. Note: This * default value has poor error correcting properties. */ this (uint polynomial = 0xEDB88320U) { for (int i = 0; i < 256; i++) { uint value = i; for (int j = 8; j > 0; j--) { version (Gim) { if (value & 1) { value >>>= 1; value ^= polynomial; } else value >>>= 1; } else { if (value & 1) { value &= 0xFFFFFFFE; value /= 2; value &= 0x7FFFFFFF; value ^= polynomial; } else { value &= 0xFFFFFFFE; value /= 2; value &= 0x7FFFFFFF; } } } table[i] = value; } } /** */ override Crc32 update (const(void[]) input) { uint r = result; // DMD optimization foreach (ubyte value; cast(const(ubyte[])) input) { auto i = cast(ubyte) r;// & 0xff; i ^= value; version (Gim) { r >>>= 8; } else { r &= 0xFFFFFF00; r /= 0x100; r &= 16777215; } r ^= table[i]; } result = r; return this; } /** The Crc32 digestSize is 4 */ override uint digestSize () { return 4; } /** */ override ubyte[] binaryDigest(ubyte[] buf = null) { if (buf.length < 4) buf.length = 4; uint v = ~result; buf[3] = cast(ubyte) (v >> 24); buf[2] = cast(ubyte) (v >> 16); buf[1] = cast(ubyte) (v >> 8); buf[0] = cast(ubyte) (v); result = 0xffffffff; return buf; } /** Returns the Crc32 digest as a uint */ uint crc32Digest() { uint ret = ~result; result = 0xffffffff; return ret; } } debug(UnitTest) { unittest { scope c = new Crc32(); static ubyte[] data = [1,2,3,4,5,6,7,8,9,10]; c.update(data); assert(c.binaryDigest() == cast(ubyte[]) x"7b572025".dup); c.update(data); assert(c.crc32Digest() == 0x2520577b); c.update(data); assert(c.hexDigest() == "7b572025".dup); } } |