''' <summary>
''' This is extended from <see cref="System.Security.Cryptography.HashAlgorithm">HashAlgorithm</see> to calculate CRC32.
''' </summary>
Public Class CRC32
    Inherits System.Security.Cryptography.HashAlgorithm

    Private Const _DefaultPolynomial As Integer = &HEDB88320

#Region " Member Variables "
    Private l_table() As Integer
    Private l_crc32 As Integer = &HFFFFFFFF
    Private l_polynomial As Integer
#End Region

#Region " Contructors "
    ''' <summary>
    ''' Initializes a new instance of the <see cref="CRC32" /> class with <see cref="HashSizeValue" /> of 32 and the default polynomial of &amp;HEDB88320.
    ''' </summary>
    Public Sub New()
        Me.HashSizeValue = 32 ' CRC32 is a 32bit hash    
        l_polynomial = _DefaultPolynomial
        Initialize()
    End Sub

    ''' <summary>
    ''' Initializes a new instance of the <see cref="CRC32" /> class with given polynomial. Do not forget to set the <see cref="HashSizeValue" /> and call the <see cref="CRC32.Initialize" /> method.
    ''' </summary>
    ''' <param name="Polynomial">The polynomial to use to build the default table..</param>
    Public Sub New(ByVal Polynomial As Integer)
        l_polynomial = Polynomial
    End Sub
#End Region

#Region " HashAlgorithm "
    Protected Overrides Sub HashCore(ByVal array() As Byte, ByVal ibStart As Integer, ByVal cbSize As Integer)
        Dim intLookup As Integer
        For i As Integer = 0 To cbSize - 1

            intLookup = (l_crc32 And &HFF) Xor array(i)
            'This is a workaround for a right bit-shift because vb.net   
            'does not support unsigned Integers, so _CRC32 >> 8               
            'gives the wrong value (any better fixes?)              
            l_crc32 = ((l_crc32 And &HFFFFFF00) \ &H100) And &HFFFFFF
            l_crc32 = l_crc32 Xor l_table(intLookup)
        Next i
    End Sub

    Protected Overrides Function HashFinal() As Byte()
        Return BitConverter.GetBytes(Not l_crc32)
    End Function

    ''' <summary>
    ''' Initializes an implementation of the <see cref="System.Security.Cryptography.HashAlgorithm" /> class.
    ''' </summary>
    Public Overrides Sub Initialize()
        l_crc32 = &HFFFFFFFF
        l_table = BuildTable(l_polynomial)
    End Sub
#End Region

#Region " Helper Methods "
    ''' <summary>
    ''' Generates the CRC32 Table
    ''' </summary>
    ''' <param name="Polynomial">A polynomial that should be used to generate the table.</param>
    ''' <returns>
    ''' The CRC32 Table based on the Polynomial given
    ''' </returns>
    Private Shared Function BuildTable(ByVal Polynomial As Integer) As Integer()
        Dim Table(255) As Integer
        Dim Value As Integer

        For I As Integer = 0 To 255
            Value = I
            For X As Integer = 0 To 7
                If (Value And 1) = 1 Then
                    'This is a workaround for a right bit-shift because vb.net    
                    'does not support unsigned Integers, so _CRC32 >> 1     
                    'gives the wrong value (any better fixes?)       
                    Value = Convert.ToInt32(((Value And &HFFFFFFFE) \ 2&) And &H7FFFFFFF)
                    Value = Value Xor Polynomial
                Else
                    'Same as above.           
                    Value = Convert.ToInt32(((Value And &HFFFFFFFE) \ 2&) And &H7FFFFFFF)
                End If
            Next
            Table(I) = Value
        Next
        Return Table
    End Function
#End Region

    ''' <summary>
    ''' Hashes to string.
    ''' </summary>
    ''' <param name="p_hash">The hash value.</param>
    ''' <returns>Resutns hash value in hex string</returns>
    Public Shared Function HashToString(ByRef p_hash() As Byte) As String
        Dim buff As New System.Text.StringBuilder
        For Each hashByte As Byte In p_hash
            buff.Append(String.Format("{0:X1}", hashByte))
        Next
        Return buff.ToString
    End Function
End Class
