#include once "window9.bi"

'SHA1Checksum - .bi-Version

'Initialisierungskonstanten
#Define H0 &H67452301
#Define H1 &Hefcdab89
#Define H2 &H98badcfe
#Define H3 &H10325476
#Define H4 &Hc3d2e1f0

'*******************************************************

#Define Ch(x,y,z) ((x And y) Xor ((Not x) And z))
#Define Maj(x,y,z) ((x And y) Xor (x And z) Xor (y And z))
#Define Par(x,y,z) (x Xor y Xor z)

#Define RotateLeft(x, n) ((x Shl n) Or (x Shr (32 - n)))

'*******************************************************

Type SHA1Checksum
  Public:
  Declare Constructor()
  Declare Destructor()
  
  Declare Sub Transform(byval inpt As UByte Ptr)
  Declare Sub Update(byval dat As UByte Ptr, byval length As ULong)
  Declare Function Final() As String
  
  Private:
  As ULong state(5)
  As ULong count(2)
  As UByte buf(64)
End Type

Constructor SHA1Checksum
  state(0) = H0
  state(1) = H1
  state(2) = H2
  state(3) = H3
  state(4) = H4
End Constructor

Destructor SHA1Checksum
  
End Destructor

Sub SHA1Checksum.Transform(byval inpt As UByte Ptr)
  Dim As ULong a, b, c, d, e, T
  Dim As ULong w(80)
  
  Dim As Long i
  
  Dim As UByte Ptr where = inpt
  For i = 0 To 15
    Dim As ULong temp = inpt[(4*i)]
    temp Shl= 8
    temp Or= inpt[(4*i) + 1]
    temp Shl= 8
    temp Or= inpt[(4*i) + 2]
    temp Shl= 8
    temp Or= inpt[(4*i) + 3]
    w(i) = temp
  Next
  
  For i = 16 To 79
    w(i) = RotateLeft((w(i-3) Xor w(i-8) Xor w(i-14) Xor w(i-16)), 1)
  Next
  
  a = state(0)
  b = state(1)
  c = state(2)
  d = state(3)
  e = state(4)
  
  For i = 0 To 19
    T = RotateLeft(a, 5) + Ch(b, c, d) + e + &H5a827999 + w(i)
    e = d
    d = c
    c = RotateLeft(b, 30)
    b = a
    a = T
  Next
  For i = 20 To 39
    T = RotateLeft(a, 5) + Par(b, c, d) + e + &H6ed9eba1 + w(i)
    e = d
    d = c
    c = RotateLeft(b, 30)
    b = a
    a = T
  Next
  For i = 40 To 59
    T = RotateLeft(a, 5) + Maj(b, c, d) + e + &H8f1bbcdc + w(i)
    e = d
    d = c
    c = RotateLeft(b, 30)
    b = a
    a = T
  Next
  For i = 60 To 79
    T = RotateLeft(a, 5) + Par(b, c, d) + e + &Hca62c1d6 + w(i)
    e = d
    d = c
    c = RotateLeft(b, 30)
    b = a
    a = T
  Next
  
  state(0) += a
  state(1) += b
  state(2) += c
  state(3) += d
  state(4) += e
End Sub

Sub SHA1Checksum.Update(byval dat As UByte Ptr, byval length As ULong)
  Dim As ULong i, index, part_len
  
  index = Cast(ULong, (count(0) Shr 3) And &H3f)
  
  count(0) += (length Shl 3)
  If (count(0) < (length Shl 3)) Then
    count(1) += 1
  EndIf
  count(1) += (length Shr 29)
  
  part_len = 64 - index
  
  If (length >= part_len) Then
    FastCopy(@buf(index), dat, part_len)
    Transform(@buf(0))
    i = part_len
    While i + 63 < length
      Transform(@dat[i])
      i += 64
    Wend
    
    index = 0
  Else
    i = 0
  EndIf
  
  FastCopy(@buf(index), @dat[i], length - i)
End Sub

Function SHA1Checksum.Final() As String
  Dim As UByte PADDING(64) => {&H80}
  Dim As UByte bits(8)
  Dim As ULong index, pad_len, t
  Dim As Long i
  
  t = count(0)
  bits( 7) = t:t Shr= 8
  bits( 6) = t:t Shr= 8
  bits( 5) = t:t Shr= 8
  bits( 4) = t
  t = count(1)
  bits( 3) = t:t Shr= 8
  bits( 2) = t:t Shr= 8
  bits( 1) = t:t Shr= 8
  bits( 0) = t
  
  index = Cast(ULong, (count(0) Shr 3) And &H3f)
  pad_len = IIf(index < 56, (56 - index), (120 - index))
  Update(@PADDING(0), pad_len)
  
  Update(@bits(0), 8)
  
  Dim As String ret
   For i = 0 To 4
     ret += Hex(state(i), 8)
   Next
   
  Return ret
End Function

Function SHA1create(ByRef text As String) As String Export
  Dim As ULong nLength = Len(text)
  If nLength = 0 Then
    Return "No text given"
  EndIf
  
  Dim As SHA1Checksum SHA1

  SHA1.Update(@text[0], nLength)
  
  Return SHA1.Final()
End Function

Function SHA1createFile(sFile As String) As String Export
	

  Dim As ULong nLength = Len(sFile)
  If nLength = 0 Then
    Return "No file specified"
  EndIf
  
  Dim As Long FFF = FreeFile
  If Open(sFile For Binary Access Read As #FFF) <> 0 Then
    Return "File not found/can't be opened"
  EndIf
  
  Dim As ULong fileLength = Lof(FFF)
  If fileLength = 0 Then
    Close #FFF
    Return "Empty file"
  EndIf
  
  Dim As UByte buffer(16384)
  Dim As ULong toBuffer
  Dim As SHA1Checksum SHA1
  Do Until fileLength = 0
    If fileLength >= 16384 Then
      fileLength -= 16384
      toBuffer = 16384
    Else
      toBuffer = fileLength
      fileLength = 0
    EndIf
    Get #FFF, , buffer(0), toBuffer
    SHA1.Update(@buffer(0), toBuffer)
  Loop
  Close #FFF
  
  Return SHA1.Final()
End Function