using System; using System.Collections.Generic; using System.IO; using System.Linq; namespace com.clusterrr.TuyaNet { /// /// Performs 32-bit reversed cyclic redundancy checks. /// internal class Crc32 { #region Constants /// /// Generator polynomial (modulo 2) for the reversed CRC32 algorithm. /// private const UInt32 s_generator = 0xEDB88320; #endregion #region Constructors /// /// Creates a new instance of the Crc32 class. /// public Crc32() { // Constructs the checksum lookup table. Used to optimize the checksum. m_checksumTable = Enumerable.Range(0, 256).Select(i => { var tableEntry = (uint)i; for (var j = 0; j < 8; ++j) { tableEntry = ((tableEntry & 1) != 0) ? (s_generator ^ (tableEntry >> 1)) : (tableEntry >> 1); } return tableEntry; }).ToArray(); } #endregion #region Methods /// /// Calculates the checksum of the byte stream. /// /// The byte stream to calculate the checksum for. /// A 32-bit reversed checksum. public UInt32 Get(IEnumerable byteStream) { try { // Initialize checksumRegister to 0xFFFFFFFF and calculate the checksum. return ~byteStream.Aggregate(0xFFFFFFFF, (checksumRegister, currentByte) => (m_checksumTable[(checksumRegister & 0xFF) ^ Convert.ToByte(currentByte)] ^ (checksumRegister >> 8))); } catch (FormatException e) { throw new InvalidDataException("Could not read the stream out as bytes.", e); } catch (InvalidCastException e) { throw new InvalidDataException("Could not read the stream out as bytes.", e); } catch (OverflowException e) { throw new InvalidDataException("Could not read the stream out as bytes.", e); } } #endregion #region Fields /// /// Contains a cache of calculated checksum chunks. /// private readonly UInt32[] m_checksumTable; #endregion } }