#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 UInteger)
	Declare Function Final() As String
	
	Private:
	As UInteger state(5)
	As UInteger 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 UInteger a, b, c, d, e, T
	Dim As UInteger w(80)
	
	Dim As Integer i
	
	Dim As UByte Ptr where = inpt
	For i = 0 To 15
		Dim As UInteger 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 UInteger)
	Dim As UInteger i, index, part_len
	
	index = Cast(UInteger, (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 UInteger index, pad_len, t
	Dim As Integer 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(UInteger, (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 UInteger nLength = Len(text)
	If nLength = 0 Then
		Return "No text given"
	EndIf
	
	Dim As UByte buffer(16384)
	For i As Integer = 1 To nLength
		buffer(i - 1) = Asc(Mid(text, i ,1))
	Next
	
	Dim As SHA1Checksum SHA1
	SHA1.Update(@buffer(0), nLength)
	
	Return SHA1.Final()
End Function

Function SHA1createFile(ByRef file As String) As String Export
	Dim As UInteger nLength = Len(file)
	If nLength = 0 Then
		Return "No file specified"
	EndIf
	
	Dim As Integer FFF = FreeFile
	If Open(file For Binary Access Read As #FFF) <> 0 Then
		Return "File not found/can't be opened"
	EndIf
	
	Dim As UInteger fileLength = Lof(FFF)
	If fileLength = 0 Then
		Close #FFF
		Return "Empty file"
	EndIf
	
	Dim As UByte buffer(16384)
	Dim As UInteger 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
