> string filename; > filename = @"M:\VM\Machines\Vfp9_Sp1\Vfp9_Sp1_D.vmdk"; > > using (Stream s = File.OpenRead(filename)) > { > var vv = new CRC32(); > crc_sliced = 0; > crc_sliced = vv.GetCRC(s); > Console.WriteLine("{0} sliced", crc_sliced.ToString("X8")); > } >>
> // must start from zero, no holes permitted > public enum CRCPolynomial > { > IEEE = 0, > Castagnoli = 1 > } >>
> public class BitSize > { > public const int BitsPerByte = 8; > public const int BitsPerByteShift = 3; > > public const int Byte = (ByteSize.Byte << BitsPerByteShift); > public const int SByte = (ByteSize.SByte << BitsPerByteShift); > > public const int Char = (ByteSize.Char << BitsPerByteShift); > > public const int Int16 = (ByteSize.Int16 << BitsPerByteShift); > public const int UInt16 = (ByteSize.UInt16 << BitsPerByteShift); > > public const int Int32 = (ByteSize.Int32 << BitsPerByteShift); > public const int UInt32 = (ByteSize.UInt32 << BitsPerByteShift); > > public const int Int64 = (ByteSize.Int64 << BitsPerByteShift); > public const int UInt64 = (ByteSize.UInt64 << BitsPerByteShift); > } >>
>#define USE_PARALLEL_TABLE_CONSTRUCTION > // Static part > public partial class CRC32 > { > #region Polynomial Definition > #region Data > //_____________________________________________________________________ > private static readonly UInt32[][] PolynomialsDefinition = > // do not change the sequence without changing enum CRCPolynomial > { // IEEE > new UInt32[] { 26, 23, 22, 16, 12, 11, 10, 8, 7, 5, 4, 2, 1, 0 }, > > //Castagnoli > new UInt32[] { 28, 27, 26, 25, 23, 22, 20, 19, 18, 14, 13, 11, 10, 9, 8, 6, 0 } > }; > > // As many elements as enum CRCPolynomial > private static readonly UInt32[] ReversePolynomial = InitReversePolynomial(); > //_____________________________________________________________________ > #endregion Data > #region Methods > private static UInt32[] InitReversePolynomial() > { > UInt32[] reversePolynomial = new UInt32[PolynomialsDefinition.Length]; > > for (int i = 0; i <= PolynomialsDefinition.GetUpperBound(0); i++) > { > > reversePolynomial[i] = GetReversePolynomial(PolynomialsDefinition[i]); > } > return reversePolynomial; > } > //______________________________________________________________________ > private static UInt32 GetReversePolynomial(UInt32[] coef) > { > UInt32 polynomial = 0; > for (int i = 0; i <= coef.GetUpperBound(0); i++) > polynomial |= 1u << (int)(31u - coef[i]); > > //Console.WriteLine("poly {0}", polynomial.ToString("X8")); > return polynomial; > } > //______________________________________________________________________ > #endregion Methods > #endregion Polynomial Definition > > > /* > * Tables are grouped by 4, since this is a crc of 32 bits > * Each set of 4 tables can 'multiply' or transform a crc a mumber of bytes to the right > * > * There are two sets of tables, but basically they do the same > * - (1) used for hashing > * see Slicing by 8 http://www.intel.com/technology/comms/perfnet/download/CRC_generators.pdf > * > * - (2) used to transform or multiply the crc of a block a number of bytes to the right > */ > > /* Each polynomial has its own set of tables > * Implemented here are IEEE and Castagnoli polynomials > * The tables are static and are only calculated on first use > */ > > > // Used to lock the access to the tables, they will be constructed the first time they are accessed > private static readonly object TableLocker = new object(); > > #region HashTables > // HashTables HashTables[CRCPolynomial.Index][tableId][elements 0-255] > private static readonly UInt32[][][] HashTables32 = new UInt32[PolynomialsDefinition.Length][][]; > > // Slicing by 16 algorithm - need 16 tables, each one = 1k, so 16k in total > private const uint HashTable32_Id_04 = 0; > private const uint HashTable32_Id_05 = 1; > private const uint HashTable32_Id_06 = 2; > private const uint HashTable32_Id_07 = 3; > private const uint HashTable32_Id_08 = 4; > private const uint HashTable32_Id_09 = 5; > private const uint HashTable32_Id_10 = 6; > private const uint HashTable32_Id_11 = 7; > private const uint HashTable32_Id_12 = 8; > private const uint HashTable32_Id_13 = 9; > private const uint HashTable32_Id_14 = 10; > private const uint HashTable32_Id_15 = 11; > private const uint HashTable32_Id_16 = 12; > private const uint HashTable32_Id_17 = 13; > private const uint HashTable32_Id_18 = 14; > private const uint HashTable32_Id_19 = 15; > > private const uint HashTable32_Id_Min = HashTable32_Id_04; > private const uint HashTable32_Id_Max = HashTable32_Id_19; > > //______________________________________________________________________ > private static void GetTables32( > CRCPolynomial polyId, > out UInt32[][] hashTables32, > out UInt32[][] transformTables32 > ) > { > UInt32 polyIndex = (UInt32) polyId; > UInt32 reversePolynomial = ReversePolynomial[polyIndex]; > > lock (TableLocker) > { > hashTables32 = GetHashTables32(polyIndex); > transformTables32 = GetTransformTables32(polyIndex); > } > } > //______________________________________________________________________ > //______________________________________________________________________ > private static UInt32[][] GetHashTables32(UInt32 polyIndex) > { > UInt32[][] hashTables32; > > if (HashTables32[polyIndex] != null) > { > hashTables32 = HashTables32[polyIndex]; > } > else > { > hashTables32 = new UInt32[HashTable32_Id_Max + 1][]; > HashTables32[polyIndex] = hashTables32; > > UInt32 reversePolynomial = ReversePolynomial[polyIndex]; > > > // Calculate the first table > hashTables32[HashTable32_Id_04] = MakeCRCTable(reversePolynomial, 4); > > //Calculate the rest by shifting the previous one one byte to the right > for (uint index = HashTable32_Id_04; ++index <= HashTable32_Id_Max; ) > hashTables32[index] = ShiftCRCTable(hashTables32[index - 1], reversePolynomial, 1); > } > > return hashTables32; > } > //______________________________________________________________________ > #endregion HashTables > > //______________________________________________________________________ > #region Thread > > //______________________________________________________________________ > #region Data > > > private static readonly int NumberOfBuffers = Environment.ProcessorCount << 3; > private const int BufferSizeEach = 16384; > private static readonly int TotalBufferSize = BufferSizeEach * NumberOfBuffers; > > > // TransformTables32[CRCPolynomial.Index][tableId 0-3 ][elements 0-255] > private static readonly UInt32[][][] TransformTables32 = new UInt32[PolynomialsDefinition.Length][][]; > //______________________________________________________________________ > #endregion Data > //______________________________________________________________________ > #region Methods > //______________________________________________________________________ > private static UInt32[][] GetTransformTables32(uint polyIndex) > { > UInt32[][] transformTables32; > > if (TransformTables32[polyIndex] != null) > { > transformTables32 = TransformTables32[polyIndex]; > } > else > { > transformTables32 = new UInt32[4][]; > TransformTables32[polyIndex] = transformTables32; > > UInt32 reversePolynomial = ReversePolynomial[polyIndex]; > > > // Calculate the first table - takes 50 - 60 ms > transformTables32[0] = MakeCRCTable(reversePolynomial, BufferSizeEach); > > //Calculate the rest by shifting the previous one one byte to the right > for (uint index = 0; ++index <= 3; ) > transformTables32[index] = ShiftCRCTable(transformTables32[index - 1], reversePolynomial, 1); > } > > return transformTables32; > } > //______________________________________________________________________ > #endregion Methods > //______________________________________________________________________ > #endregion Thread > //______________________________________________________________________ > //______________________________________________________________________ > #region Table Common methods > //______________________________________________________________________ > private static UInt32[] MakeCRCTable(UInt32 reversePolynomial, uint byteOffset) > { > if (byteOffset < 4) > throw new ArgumentOutOfRangeException("byteOffset", " >= 4"); > > UInt32[] table = new UInt32[byte.MaxValue + 1]; > > > // loop is Parallel candidate > >#if !USE_PARALLEL_TABLE_CONSTRUCTION > UInt32 remainder; > for (uint i = byte.MinValue; i <= byte.MaxValue; i++) > { > remainder = i; > for( int offset = (int)byteOffset - 4 + 1; --offset >= 0; ) > remainder = ProcessRemainderByte(reversePolynomial, remainder); > > table[i] = remainder; > > } >#else > Parallel.For(byte.MinValue, byte.MaxValue + 1, i => > { > UInt32 remainder = unchecked((UInt32)i); > for (int offset = (int)byteOffset - 4 + 1; --offset >= 0; ) > remainder = ProcessRemainderByte(reversePolynomial, remainder); > > table[i] = remainder; > > } > ); >#endif > return table; > } > //______________________________________________________________________ > private static UInt32 ProcessRemainderByte(UInt32 reversePolynomial, UInt32 remainder) > { > for (int bits = BitSize.Byte; --bits >= 0; ) > remainder = (remainder & (0x01u)) != 0 ? reversePolynomial ^ (remainder >> 1) : (remainder >> 1); > > return remainder; > } > //______________________________________________________________________ > private static UInt32[] ShiftCRCTable(UInt32[] tableIn, UInt32 reversePolynomial, UInt32 nBytes) > { > if (nBytes < 1) > throw new ArgumentOutOfRangeException("nBytes", " >= 1"); > > UInt32[] tableOut = new UInt32[tableIn.Length]; > > > > // loop is Parallel candidate >#if !USE_PARALLEL_TABLE_CONSTRUCTION > UInt32 remainder; > for (int i = tableIn.Length; --i >= 0; ) > { > remainder = tableIn[i]; > for( int count = (int) nBytes; --count >= 0; ) > remainder = ProcessRemainderByte(reversePolynomial, remainder); > > tableOut[i] = remainder; > } >#else > Parallel.For(0, tableIn.Length, i => > { > UInt32 remainder = unchecked(tableIn[(UInt32)i]); > for (int count = (int)nBytes; --count >= 0; ) > remainder = ProcessRemainderByte(reversePolynomial, remainder); > > tableOut[i] = remainder; > } > ); >#endif > return tableOut; > } > //______________________________________________________________________ > #endregion Table Common methods > > } >>
>#define USE_PARALLEL_CRC_CALCULATION > > public partial class CRC32 > { > //______________________________________________________________________ > // tables for hashing > private UInt32[] Hash_04; > private UInt32[] Hash_05; > private UInt32[] Hash_06; > private UInt32[] Hash_07; > private UInt32[] Hash_08; > private UInt32[] Hash_09; > private UInt32[] Hash_10; > private UInt32[] Hash_11; > private UInt32[] Hash_12; > private UInt32[] Hash_13; > private UInt32[] Hash_14; > private UInt32[] Hash_15; > private UInt32[] Hash_16; > private UInt32[] Hash_17; > private UInt32[] Hash_18; > private UInt32[] Hash_19; > > // tables for Transformation > private UInt32[] Transform_4096_00; > private UInt32[] Transform_4096_01; > private UInt32[] Transform_4096_02; > private UInt32[] Transform_4096_03; > > private const UInt32 CRC32InitValue = 0xffffffff; > //______________________________________________________________________ > #region Constructors > //______________________________________________________________________ > public CRC32() > : this(CRCPolynomial.IEEE) > { > } > //______________________________________________________________________ > public CRC32(CRCPolynomial poly) > : base() > { > // get the tables > UInt32[][] hash, transform; > > GetTables32(poly, out hash, out transform); > > Hash_04 = hash[HashTable32_Id_04]; > Hash_05 = hash[HashTable32_Id_05]; > Hash_06 = hash[HashTable32_Id_06]; > Hash_07 = hash[HashTable32_Id_07]; > Hash_08 = hash[HashTable32_Id_08]; > Hash_09 = hash[HashTable32_Id_09]; > Hash_10 = hash[HashTable32_Id_10]; > Hash_11 = hash[HashTable32_Id_11]; > > Hash_12 = hash[HashTable32_Id_12]; > Hash_13 = hash[HashTable32_Id_13]; > Hash_14 = hash[HashTable32_Id_14]; > Hash_15 = hash[HashTable32_Id_15]; > Hash_16 = hash[HashTable32_Id_16]; > Hash_17 = hash[HashTable32_Id_17]; > Hash_18 = hash[HashTable32_Id_18]; > Hash_19 = hash[HashTable32_Id_19]; > > Transform_4096_00 = transform[0]; > Transform_4096_01 = transform[1]; > Transform_4096_02 = transform[2]; > Transform_4096_03 = transform[3]; > > } > //______________________________________________________________________ > #endregion > #region GetCRC > public Int32 GetCRC(Stream stream) > { > UInt32 crcCurrent = CRC32InitValue; > > byte[] buf = new byte[TotalBufferSize]; > UInt32[] bufferCRC = new UInt32[NumberOfBuffers]; > > int count; > while( (count = stream.Read(buf, 0, TotalBufferSize)) > 0 ) > { > if (count < TotalBufferSize) > { > crcCurrent = HashBlock16(crcCurrent, buf, 0, count); > break; > } > > GetBufferCRC(bufferCRC, buf); > crcCurrent = MergeCRCs(crcCurrent, bufferCRC); > } > > > return unchecked((Int32)~crcCurrent); > } > //______________________________________________________________________ > // parallel candidate > private void GetBufferCRC(UInt32[] threadCRC, byte[] buf) > { >#if !USE_PARALLEL_CRC_CALCULATION > > int offset = 0; > for (int i = 0; i < NumberOfBuffers; i++, offset += BufferSizeEach) > { > threadCRC[i] = HashBlock16(0, buf, offset, BufferSizeEach); > } >#else > Parallel.For(0, NumberOfBuffers, i => > { > int offset = i * BufferSizeEach; > threadCRC[i] = HashBlock16(0, buf, offset, BufferSizeEach); > } > ); > >#endif > > } > //______________________________________________________________________ > /* > */ > private UInt32 MergeCRCs(UInt32 crcCurrent, UInt32[] bufferCRC) > { > for (int i = 0; i < NumberOfBuffers; i++ ) > crcCurrent = TransformCRC(crcCurrent) ^ bufferCRC[i]; > > return crcCurrent; > } > //______________________________________________________________________ > #endregion > #region Hashing > //______________________________________________________________________ > // Slicing by 16 > private UInt32 HashBlock16(UInt32 crc, byte[] buf, int offset, int count) > { > > // head > for (int i = count >> 4; --i >= 0; offset += 16) > { > crc ^= ((UInt32)buf[offset + 3] << 24) > | ((UInt32)buf[offset + 2] << 16) > | ((UInt32)buf[offset + 1] << 8) > | ((UInt32)buf[offset]); > > crc = Hash_19[crc & 0xFF] > ^ Hash_18[(crc >> 8) & 0xFF] > ^ Hash_17[(crc >> 16) & 0xFF] > ^ Hash_16[(crc >> 24) ] > ^ Hash_15[buf[offset + 4]] > ^ Hash_14[buf[offset + 5]] > ^ Hash_13[buf[offset + 6]] > ^ Hash_12[buf[offset + 7]] > ^ Hash_11[buf[offset + 8]] > ^ Hash_10[buf[offset + 9]] > ^ Hash_09[buf[offset + 10]] > ^ Hash_08[buf[offset + 11]] > ^ Hash_07[buf[offset + 12]] > ^ Hash_06[buf[offset + 13]] > ^ Hash_05[buf[offset + 14]] > ^ Hash_04[buf[offset + 15]]; > } > > // tail > int tailCycles; > > if ((tailCycles = count & 0x0f) != 0) > for (int i = tailCycles; --i >= 0; ) > crc = Hash_04[(crc ^ (UInt32)buf[offset++]) & 0xFF] ^ (crc >> 8); > > return crc; > > } > //______________________________________________________________________ > #endregion > #region TransformCRC > UInt32 TransformCRC(UInt32 crc) > { > return Transform_4096_03[crc & 0xFF] > ^ Transform_4096_02[(crc >> 8) & 0xFF] > ^ Transform_4096_01[(crc >> 16) & 0xFF] > ^ Transform_4096_00[(crc >> 24)]; > } > //______________________________________________________________________ > #endregion > } >