Using Digest=#True for the XXH32_Update procedure does not affect State.
With the XXH32_Update procedure you can generate an intermediate hash, add more bytes and generate a new hash.
Code: Select all
; XXH32 module by Wilbert
; A PureBasic port of the XXH32 algorithm
; The XXH32 algorithm was created by Yann Collet
; Last code update : May 23, 2018
; Callback for XXH32_FromFile:
; Procedure ProgressCallback(BytesRead.q, FileSize.q, UserData)
DeclareModule XXH32
Structure XXH32_State ; structure size = 40 bytes
v.l[4] ; offset 0
memory.l[4] ; offset 16
total_len.q ; offset 32
EndStructure
Declare.s XXH32_Hex(Value.l)
Declare.l XXH32(*Buffer, Size, Seed=0)
Declare XXH32_Init(*State, Seed=0)
Declare.l XXH32_Update(*State, *Buffer, Size, Digest=#False)
Declare.l XXH32_FromFile(Filename.s, Seed=0, *ProgressCallback=0, UserData=0)
EndDeclareModule
Module XXH32
EnableExplicit
DisableDebugger
EnableASM
CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
Macro rbx : ebx : EndMacro
Macro rsi : esi : EndMacro
Macro rdi : edi : EndMacro
Macro rsp : esp : EndMacro
Macro rbp : ebp : EndMacro
CompilerEndIf
Macro M_XXH32_Hex(o1, o2)
!movzx eax, byte [p.v_Value+o1]
!movzx ecx, byte [p.v_Value+o1+1]
!shl ecx, 16
!or eax, ecx
!mov ecx, eax
!shl ecx, 4
!or eax, ecx
!and eax, 0x0f0f0f0f
!lea ecx, [eax + 0x06060606]
!or eax, 0x30303030
!shr ecx, 4
!and ecx, 0x01010101
!imul ecx, 0x27
!add eax, ecx
!bswap eax
!mov [p.v_Result+o2], eax
EndMacro
Procedure.s XXH32_Hex(Value.l)
Protected Result.q
M_XXH32_Hex(0, 4)
M_XXH32_Hex(2, 0)
ProcedureReturn PeekS(@Result, 8, #PB_Ascii)
EndProcedure
Macro M_XXH32_Process(lane)
imul ebp, [rsi], 0x85ebca77 ; accN = accN + (laneN * prime32_2)
add rsi, 4
!add lane, ebp
!rol lane, 13 ; accN = accN <<< 13
!imul lane, 0x9e3779b1 ; accN = accN * prime32_1
EndMacro
Macro M_XXH32_Final(shift)
!mov ecx, eax ; acc = acc xor (acc >> shift)
!shr ecx, shift
!xor eax, ecx
EndMacro
Procedure.l XXH32(*Buffer, Size, Seed=0)
mov [rsp-8], rsi
mov [rsp-16], rdi
mov rsi, [p.p_Buffer]
mov rdi, [p.v_Size]
sub rdi, 16
!jnc .init
; size < 16
!mov eax, [p.v_Seed]
!add eax, 0x165667b1 ; acc = seed + prime32_5
!jmp .add_size
; initialize internal accumulators
!.init:
mov [rsp-24], rbx
mov [rsp-32], rbp
!mov ecx, [p.v_Seed] ; acc3 = seed
!lea eax, [ecx + 0x24234428] ; acc1 = seed + (prime32_1 + prime32_2)
!lea ebx, [ecx + 0x85ebca77] ; acc2 = seed + prime32_2
!lea edx, [ecx + 0x61c8864f] ; acc4 = seed + (-prime32_1)
; process stripes
!.process:
M_XXH32_Process(eax)
M_XXH32_Process(ebx)
M_XXH32_Process(ecx)
M_XXH32_Process(edx)
sub rdi, 16
!jnc .process
; accumulator convergence
!rol eax, 1 ; acc = (acc1 <<< 1) + (acc2 << 7) + (acc3 << 12) + (acc4 << 18)
!rol ebx, 7
!add eax, ebx
!rol ecx, 12
!add eax, ecx
!rol edx, 18
!add eax, edx
mov rbp, [rsp-32]
mov rbx, [rsp-24]
; add size
!.add_size:
!add eax, [p.v_Size]
; consume remaining input
add rdi, 16
sub rdi, 4
!jnc .consume4
add rdi, 4
!jz .final_mix
!jmp .consume1
!.consume4:
imul ecx, [rsi], 0xc2b2ae3d ; acc = acc + lane * prime32_3
add rsi, 4
!add eax, ecx
!rol eax, 17 ; acc = (acc <<< 17) * prime32_4
!imul eax, 0x27d4eb2f
sub rdi, 4
!jnc .consume4
add rdi, 4
!jz .final_mix
!.consume1:
movzx ecx, byte [rsi] ; acc = acc + lane * prime32_5
add rsi, 1
!imul ecx, 0x165667b1
!add eax, ecx
!rol eax, 11 ; acc = (acc <<< 11) * prime32_1
!imul eax, 0x9e3779b1
sub rdi, 1
!jnz .consume1
; final mix
!.final_mix:
M_XXH32_Final(15) ; acc = acc xor (acc >> 15)
!imul eax, 0x85ebca77 ; acc = acc * prime32_2
M_XXH32_Final(13) ; acc = acc xor (acc >> 13)
!imul eax, 0xc2b2ae3d ; acc = acc * prime32_3
M_XXH32_Final(16) ; acc = acc xor (acc >> 16)
mov rdi, [rsp-16]
mov rsi, [rsp-8]
ProcedureReturn
EndProcedure
Procedure.l XXH32_ROL(v.l, n.l)
!mov eax, [p.v_v]
!mov ecx, [p.v_n]
!rol eax, cl
ProcedureReturn
EndProcedure
Procedure XXH32_Init(*State.XXH32_State, Seed=0)
*State\v[0] = Seed + $24234428 ; acc1 = seed + (prime32_1 + prime32_2)
*State\v[1] = Seed + $85ebca77 ; acc2 = seed + prime32_2
*State\v[2] = Seed ; acc3 = seed
*State\v[3] = Seed + $61c8864f ; acc4 = seed + (-prime32_1)
*State\total_len = 0
EndProcedure
Procedure.l XXH32_Update(*State.XXH32_State, *Buffer, Size, Digest=#False)
Protected.l acc, i, n, mempos = *State\total_len & 15
*State\total_len + Size
If mempos
If mempos + Size < 16
CopyMemory(*Buffer, @*State\memory + mempos, Size)
Size = 0
Else
n = 16 - mempos
CopyMemory(*Buffer, @*State\memory + mempos, n)
*State\v[0] = XXH32_ROL(*State\v[0] + *State\memory[0] * $85ebca77, 13) * $9e3779b1
*State\v[1] = XXH32_ROL(*State\v[1] + *State\memory[1] * $85ebca77, 13) * $9e3779b1
*State\v[2] = XXH32_ROL(*State\v[2] + *State\memory[2] * $85ebca77, 13) * $9e3779b1
*State\v[3] = XXH32_ROL(*State\v[3] + *State\memory[3] * $85ebca77, 13) * $9e3779b1
*Buffer + n
Size - n
EndIf
EndIf
n = Size & 15
If n
CopyMemory(*Buffer + Size - n, @*State\memory, n)
Size - n
EndIf
If Size
; load state
mov [rsp-8], rsi
mov [rsp-16], rdi
mov [rsp-24], rbx
mov [rsp-32], rbp
mov rdi, [p.p_State]
mov eax, [rdi]
mov ebx, [rdi+4]
mov ecx, [rdi+8]
mov edx, [rdi+12]
mov rsi, [p.p_Buffer]
mov rdi, [p.v_Size]
; process stripes
!.process:
M_XXH32_Process(eax)
M_XXH32_Process(ebx)
M_XXH32_Process(ecx)
M_XXH32_Process(edx)
sub rdi, 16
!jnz .process
; save state
mov rdi, [p.p_State]
mov [rdi], eax
mov [rdi+4], ebx
mov [rdi+8], ecx
mov [rdi+12], edx
mov rbp, [rsp-32]
mov rbx, [rsp-24]
mov rdi, [rsp-16]
mov rsi, [rsp-8]
EndIf
If Digest
; accumulator convergence
If *State\total_len < 16
acc = *State\v[2] + $165667b1
Else
acc = XXH32_ROL(*State\v[0], 1) + XXH32_ROL(*State\v[1], 7) +
XXH32_ROL(*State\v[2], 12) + XXH32_ROL(*State\v[3], 18)
EndIf
; add size
acc + *State\total_len
; consume remaining input
n = *State\total_len & 15
While n >= 4
acc = XXH32_ROL(acc + *State\memory[i] * $c2b2ae3d, 17) * $27d4eb2f
i + 1
n - 4
Wend
i = *State\memory[i]
While n
acc = XXH32_ROL(acc + (i & $ff) * $165667b1, 11) * $9e3779b1
i >> 8
n - 1
Wend
; final mix
!mov eax, [p.v_acc]
M_XXH32_Final(15) ; acc = acc xor (acc >> 15)
!imul eax, 0x85ebca77 ; acc = acc * prime32_2
M_XXH32_Final(13) ; acc = acc xor (acc >> 13)
!imul eax, 0xc2b2ae3d ; acc = acc * prime32_3
M_XXH32_Final(16) ; acc = acc xor (acc >> 16)
ProcedureReturn
Else
ProcedureReturn 0
EndIf
EndProcedure
#BufferSize = 65536; 64 KiB buffer
Prototype ProgressCallback(BytesRead.q, FileSize.q, UserData)
Procedure.l XXH32_FromFile(Filename.s, Seed=0, *ProgressCallback=0, UserData=0)
Protected Result.l, File.i, FSize.q, BytesRead.i
Protected *Buffer, State.XXH32_State
Protected *P.ProgressCallback, Block.i, Time.i, PrevTime.i, Elapsed.u
File = ReadFile(#PB_Any, Filename, #PB_File_SharedRead)
If File
FSize = Lof(File)
*Buffer = AllocateMemory(#BufferSize, #PB_Memory_NoClear)
If *Buffer
*P = *ProgressCallback
XXH32_Init(@State, Seed)
BytesRead = ReadData(File, *Buffer, #BufferSize)
While BytesRead = #BufferSize
XXH32_Update(@State, *Buffer, #BufferSize)
BytesRead = ReadData(File, *Buffer, #BufferSize)
If *P
Block + 1
If Block & $f = 0
Time = ElapsedMilliseconds()
Elapsed = Time - PrevTime
If Elapsed > 500
*P(State\total_len, FSize, UserData)
PrevTime = Time
EndIf
EndIf
EndIf
Wend
CloseFile(File)
Result = XXH32_Update(@State, *Buffer, BytesRead, #True)
FreeMemory(*Buffer)
If *P
*P(State\total_len, FSize, UserData)
EndIf
EndIf
ProcedureReturn Result
EndIf
ProcedureReturn 0
EndProcedure
EndModule
Code: Select all
s.s = "The quick brown fox jumps over the lazy dog."
size = Len(s)
*mem = AllocateMemory(size)
PokeS(*mem, s, -1, #PB_Ascii)
UseModule XXH32
Debug XXH32_Hex(XXH32(*mem, size))
Code: Select all
UseModule XXH32
Enumeration #PB_Event_FirstCustomValue
#EventProgress
#EventFinished
EndEnumeration
Global Filename.s, Busy
Procedure ProgressCallback(BytesRead.q, FileSize.q, UserData)
PostEvent(#EventProgress, 0, 0, 0, 100*BytesRead/FileSize)
EndProcedure
Procedure ComputeXXH32(*Value)
PostEvent(#EventFinished, 0, 0, 0, XXH32_FromFile(Filename, 0, @ProgressCallback()))
EndProcedure
OpenWindow(0, 0, 0, 320, 130, "XXH32", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
ButtonGadget(0, 10, 10, 300, 30, "Select file")
StringGadget(1, 10, 50, 300, 30, "", #PB_String_ReadOnly)
ProgressBarGadget(2, 10, 90, 300, 30, 0, 100, #PB_ProgressBar_Smooth)
Repeat
Event = WaitWindowEvent()
Select Event
Case #PB_Event_Gadget
If EventGadget() = 0 And Not Busy
Busy = #True
Filename = OpenFileRequester("Select file", "", "*.*", 0)
SetGadgetText(1, GetFilePart(Filename))
CreateThread(@ComputeXXH32(), 0)
EndIf
Case #EventProgress
SetGadgetState(2, EventData())
Case #EventFinished
SetGadgetText(1, "[" + XXH32_Hex(EventData()) + "] " + GetGadgetText(1))
Busy = #False
EndSelect
Until Event = #PB_Event_CloseWindow