Delphi FNV的实施
我正在尝试从实现FNV哈希 我将该页面上PowerBasic的内联asm转换为DelphiDelphi FNV的实施,delphi,fnv,Delphi,Fnv,我正在尝试从实现FNV哈希 我将该页面上PowerBasic的内联asm转换为Delphi function ReadFileToMem(sPath:string):Pointer; var hFile: THandle; pBuffer: Pointer; dSize: DWORD; dRead: DWORD; begin hFile := CreateFile(PChar(sPath), GENERIC_RE
function ReadFileToMem(sPath:string):Pointer;
var
hFile: THandle;
pBuffer: Pointer;
dSize: DWORD;
dRead: DWORD;
begin
hFile := CreateFile(PChar(sPath), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
if hFile <> 0 then
dSize := GetFileSize(hFile, nil);
if dSize <> 0 then
begin
SetFilePointer(hFile, 0, nil, FILE_BEGIN);
GetMem(Result, dSize);
ReadFile(hFile, Result^, dSize, dRead, nil);
if dRead = 0 then
MessageBox(0, PChar('Error reading file.'), PChar('Read Error'), MB_ICONEXCLAMATION)
end;
CloseHandle(hFile);
end;
function GetPointerSize(lpBuffer: Pointer): Cardinal; // Function by ErazerZ
begin
if lpBuffer = nil then
Result := Cardinal(-1)
else
Result := Cardinal(Pointer(Cardinal(lpBuffer) -4)^) and $7FFFFFFC -4;
end;
FUNCTION FNV32( dwOffset : Pointer; dwLen : DWORD; offset_basis : DWORD) : DWORD ;
asm
mov esi, dwOffset //;esi = ptr to buffer
mov ecx, dwLen //;ecx = length of buffer (counter)
mov eax, offset_basis //;set to 2166136261 for FNV-1
mov edi, 16777619//&h01000193 //;FNV_32_PRIME = 16777619
xor ebx, ebx //;ebx = 0
@nextbyte:
mul edi //;eax = eax * FNV_32_PRIME
mov bl, [esi] //;bl = byte from esi
xor eax, ebx //;al = al xor bl
inc esi //;esi = esi + 1 (buffer pos)
dec ecx //;ecx = ecx - 1 (counter)
jnz @nextbyte //;if ecx is 0, jmp to NextByte
mov @result, eax //;else, function = eax
end;
procedure TForm1.Button1Click(Sender: TObject);
var
pFile : Pointer;
hFile : Cardinal;
begin
//Profiler1['Test'].Start;
pFile := ReadFileToMem(fn);
hFile := FNV32(pFile,GetPointerSize(pFile),2166136261);
//Profiler1['Test'].Stop;
//OutputDebugString(pchar(Profiler1['Test'].AsText[tiAll]));
OutputDebugString(pchar(inttostr(hFile)));
end;
函数ReadFileToMem(sPath:string):指针;
变量
hFile:THandle;
pBuffer:指针;
dSize:DWORD;
恐惧:德沃德;
开始
hFile:=CreateFile(PChar(sPath)、GENERIC_READ、FILE_SHARE_READ、nil、OPEN_EXISTING、0、0);
如果文件为0,则
dSize:=GetFileSize(hFile,nil);
如果dSize为0,则
开始
SetFilePointer(hFile、0、nil、FILE_BEGIN);
GetMem(结果,dSize);
ReadFile(hFile、Result^、dSize、dRead、nil);
如果恐惧=0,则
MessageBox(0,PChar('读取文件时出错'),PChar('读取错误'),MB_图标连接)
终止
闭合手柄(hFile);
终止
函数GetPointerSize(lpBuffer:Pointer):基数;//ErazerZ函数
开始
如果lpBuffer=nil,则
结果:=基数(-1)
其他的
结果:=基数(指针(基数(lpBuffer)-4^)和$7ffffc-4;
终止
函数FNV32(dwOffset:Pointer;dwLen:DWORD;offset\u base:DWORD):DWORD;
asm
mov-esi,dwOffset/;esi=ptr至缓冲器
mov-ecx,dwLen/;ecx=缓冲区的长度(计数器)
mov eax,抵销基数/;FNV-1设置为2166136261
mov edi,16777619/&h01000193/;FNV_32_素数=16777619
xor-ebx,ebx/;ebx=0
@下一个字节:
mul-edi/;eax=eax*FNV_32_素数
mov bl,[esi]/;bl=来自esi的字节
异或eax,ebx/;al=al-xor-bl
公司esi/;esi=esi+1(缓冲区位置)
12月ecx/;ecx=ecx-1(计数器)
jnz@nextbyte/;如果ecx为0,则jmp到下一个字节
mov@result,eax/;否则,函数=eax
终止
程序TForm1.按钮1单击(发送方:TObject);
变量
pFile:指针;
红衣主教;
开始
//Profiler1['Test']。开始;
pFile:=ReadFileToMem(fn);
hFile:=FNV32(pFile,GetPointerSize(pFile),2166136261);
//Profiler1[“测试”]。停止;
//OutputDebugString(pchar(Profiler1['Test'].AsText[tiAll]);
OutputDebugString(pchar(inttostr(hFile));
终止
如果给定文件的大小超过200KB,则输出为随机(哈希)数。我错过了什么吗?我应该从哪里开始 1) CreateFile在失败时返回无效的\u句柄\u值,而不是0 2) SetFilePointer不是必需的 3) 如果必须散列16 GB文件,该怎么办 4) 您没有释放分配的内存-FreeMem(pFile) 5) GetPointerSize完全是个黑客。您可以从ReadFileToMem返回文件大小 下面的代码是对您的方法的重写。它仍然将完整的文件加载到内存中,但采用“Delphi方式”实现
我应该从哪里开始 1) CreateFile在失败时返回无效的\u句柄\u值,而不是0 2) SetFilePointer不是必需的 3) 如果必须散列16 GB文件,该怎么办 4) 您没有释放分配的内存-FreeMem(pFile) 5) GetPointerSize完全是个黑客。您可以从ReadFileToMem返回文件大小 下面的代码是对您的方法的重写。它仍然将完整的文件加载到内存中,但采用“Delphi方式”实现
你的asm代码有点错误。它将使您的应用程序在编写时崩溃
- 您需要保存esi/edi/ebx寄存器
- 参数在eax、ecx、edx寄存器中传递
- 结果是eax寄存器
你的asm代码有点错误。它将使您的应用程序在编写时崩溃
- 您需要保存esi/edi/ebx寄存器
- 参数在eax、ecx、edx寄存器中传递
- 结果是eax寄存器
使用标准的TMemoryStream.LoadFromFile()方法将阻止使用此ReadFileToMem子函数。您好,谢谢。我只是在学习这个。我试着用google找出如何不将完整的文件加载到内存中,我想我必须使用CreateFileMapping,对吗?如果你的数据很大,CreateFileMapping是一个很好的选择。对于大小小于200 MB的文件,我想您不会看到与现代PC有任何区别,因为内存映射文件的瓶颈将是从硬盘读取。使用标准的TMemoryStream.LoadFromFile()方法将阻止使用此ReadFileToMem子函数。您好,谢谢。我只是在学习这个。我试着用google找出如何不将完整的文件加载到内存中,我想我必须使用CreateFileMapping,对吗?如果你的数据很大,CreateFileMapping是一个很好的选择。对于大小<200 MB的文件,我想您不会看到与现代PC的任何区别,因为内存映射文件的瓶颈将是从硬盘读取。谢谢您的回复。我还尝试了上面链接中的另一个asm代码,但我总是遇到访问冲突。您是否在我们的fnv32版本中尝试了fnv32文件函数?我尝试了fnv32文件和第二个fnv32函数,它可以工作。事实上,我已经从explainth.at获得了fnv32的纯pascal版本,但是你说“纯pascal版本不会慢很多”。嗯……是的,我相信你是对的。谢谢你的回复。我还尝试了上面链接中的另一个asm代码,但我总是遇到访问冲突。您是否在我们的fnv32版本中尝试了fnv32文件函数?我尝试了fnv32文件和第二个fnv32函数,它可以工作。阿克图
function ReadFileToMem(const sPath: string; var buffer: TMemoryStream): boolean;
var
fileStr: TFileStream;
begin
Result := false;
try
fileStr := TFileStream.Create(sPath, fmOpenRead);
try
buffer.Size := 0;
buffer.CopyFrom(fileStr, 0);
finally FreeAndNil(fileStr); end;
Result := true;
except
on E: EFOpenError do
ShowMessage('Error reading file. ' + E.Message);
end;
end;
function FNV32(dwOffset: pointer; dwLen: cardinal; offset_basis: cardinal): cardinal;
asm
mov esi, dwOffset //;esi = ptr to buffer
mov ecx, dwLen //;ecx = length of buffer (counter)
mov eax, offset_basis //;set to 2166136261 for FNV-1
mov edi, 16777619//&h01000193 //;FNV_32_PRIME = 16777619
xor ebx, ebx //;ebx = 0
@nextbyte:
mul edi //;eax = eax * FNV_32_PRIME
mov bl, [esi] //;bl = byte from esi
xor eax, ebx //;al = al xor bl
inc esi //;esi = esi + 1 (buffer pos)
dec ecx //;ecx = ecx - 1 (counter)
jnz @nextbyte //;if ecx is 0, jmp to NextByte
mov @result, eax //;else, function = eax
end;
procedure TForm16.Button1Click(Sender: TObject);
var
hFile : cardinal;
memBuf: TMemoryStream;
begin
memBuf := TMemoryStream.Create;
try
if ReadFileToMem('SomeFile', memBuf) then begin
hFile := FNV32(memBuf.Memory, memBuf.Size, 2166136261);
ShowMessageFmt('Hash = %d', [hFile]);
end;
finally FreeAndNil(memBuf); end;
end;
function fnv32(dwOffset : Pointer; dwLen : DWORD; offset_basis: DWORD) : DWORD ;
asm // eax=dwOffset ecx=dwLen edx=offset_basis -> result in eax
push esi
push edi
mov esi,eax
mov eax,edx
or ecx,ecx
je @z
mov edi,16777619
xor edx,edx
@1:
mul edi
mov dl,[esi]
xor eax,edx
inc esi
dec ecx
jnz @1
@z:
pop edi
pop esi
end;
function fnv32file(const aFileName: TFileName): DWORD;
begin
with TMemoryStream.Create do
try
LoadFromFile(aFileName);
result := fnv32(Memory,Size,0);
finally
Free;
end;
end;
function fnv32(dwOffset : PByteArray; dwLen : DWORD; offset_basis: DWORD): DWORD ;
var i: integer;
begin
result := offset_basis;
for i := 0 to dwLen-1 do
result := (result*16777619) xor DWORD(dwOffset^[i]);
end;
function fnv(dwOffset : Pointer; dwLen : NativeUInt; offset_basis: NativeUInt) : NativeUInt ;
//
// http://find.fnvhash.com/ - FNV Hash Calculator Online
// http://www.isthe.com/chongo/tech/comp/fnv/
//
// The offset_basis for FNV-1 is dependent on n, the size of the hash:
// 32 bit offset_basis = 2166136261
// 64 bit offset_basis = 14695981039346656037
//
{$IF Defined(CPUX86)}
asm
push ebp
push edi
push ebx // statement must preserve the EDI, ESI, ESP, EBP, and EBX registers
mov ebp, edx
mov edx, ecx // but can freely modify the EAX, ECX, and EDX registers
mov ecx, eax
mov eax, edx
mov edi, 01000193h
xor ebx, ebx
@@nexta:
mov bl, byte ptr [ecx]
xor eax, ebx
mul edi
inc ecx
dec ebp
jnz @@nexta
pop ebx
pop edi
pop ebp
end;
{$ELSEIF Defined(CPUX64)}
asm
mov rax, R8
mov r8, rdx
mov r9, 100000001b3h
xor r10, r10
@@nexta:
mov r10b, byte ptr [rcx]
xor rax, r10
mul r9
inc rcx
dec r8
jnz @@nexta
end;
{$IFEND}