doublecmd/src/uhash.pas
2025-11-03 13:45:53 +03:00

212 lines
6.8 KiB
ObjectPascal

{
Double Commander
-------------------------------------------------------------------------
General Hash Unit: This unit defines the common types, functions,
and procedures
Copyright (C) 2009-2024 Alexander Koblov (alexx2000@mail.ru)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
}
unit uHash;
{$mode delphi}
interface
uses
Classes, SysUtils, DCPcrypt2, crc;
type
THashContext = TDCP_hash;
THashAlgorithm = (HASH_BLAKE2S, HASH_BLAKE2SP, HASH_BLAKE2B, HASH_BLAKE2BP, HASH_BLAKE3,
HASH_CHECKSUM32, HASH_CRC32, HASH_HAVAL, HASH_MD4, HASH_MD5, HASH_RIPEMD128, HASH_RIPEMD160,
HASH_SFV, HASH_SHA1, HASH_SHA224, HASH_SHA256, HASH_SHA384, HASH_SHA512,
HASH_SHA3_224, HASH_SHA3_256, HASH_SHA3_384, HASH_SHA3_512, HASH_TIGER, HASH_XXH3_128,
HASH_BEST
);
var
HashFileExt: array[Low(THashAlgorithm)..Pred(High(THashAlgorithm))] of String = (
'blake2s', 'blake2sp', 'blake2b', 'blake2bp', 'blake3', 'checksum32', 'crc32', 'haval',
'md4', 'md5', 'ripemd128', 'ripemd160', 'sfv', 'sha', 'sha224', 'sha256',
'sha384', 'sha512', 'sha3', 'sha3', 'sha3', 'sha3', 'tiger', 'xxh128'
);
var
HashName: array[Low(THashAlgorithm)..Pred(High(THashAlgorithm))] of String = (
'blake2s', 'blake2sp', 'blake2b', 'blake2bp', 'blake3', 'checksum32', 'crc32', 'haval',
'md4', 'md5', 'ripemd128', 'ripemd160', 'sfv', 'sha1_160', 'sha2_224',
'sha2_256', 'sha2_384', 'sha2_512', 'sha3_224', 'sha3_256',
'sha3_384', 'sha3_512', 'tiger', 'xxh3_128'
);
HashFirst: array[0..11] of THashAlgorithm = (
HASH_SFV, HASH_SHA224, HASH_SHA3_224,
HASH_BLAKE3, HASH_SHA256, HASH_SHA3_256,
HASH_XXH3_128, HASH_SHA384, HASH_SHA3_384,
HASH_SHA1, HASH_SHA512, HASH_SHA3_512
);
procedure HashInit(out Context: THashContext; Algorithm: THashAlgorithm);
procedure HashUpdate(var Context: THashContext; const Buffer; BufLen: LongWord);
procedure HashFinal(var Context: THashContext; out Hash: String);
function HashString(const Line: String; IgnoreCase, IgnoreWhiteSpace: Boolean): LongWord;
{ Helper functions }
function TrimHash(const AHash: String): String;
function FileExtIsHash(const FileExt: String): Boolean;
function FileExtToHashAlg(const FileExt: String): THashAlgorithm;
implementation
uses
LazUTF8, DCPhaval, DCPmd4, DCPmd5, DCPripemd128, DCPripemd160, DCPChecksum32, DCPcrc32,
DCPsha1, DCPsha256, DCPsha512, DCPtiger, DCPblake2, DCPblake3, DCPsha3, DCPxxh3;
procedure HashInit(out Context: THashContext; Algorithm: THashAlgorithm);
begin
if (Algorithm = HASH_BEST) then
begin
{$IF DEFINED(CPUX86_64)}
Algorithm:= HASH_BLAKE3;
{$ELSEIF DEFINED(CPUAARCH64)}
Algorithm:= HASH_BLAKE3;
{$ELSEIF DEFINED(CPU64)}
Algorithm:= HASH_BLAKE2B;
{$ELSE}
Algorithm:= HASH_BLAKE2S;
{$ENDIF}
end;
case Algorithm of
HASH_BLAKE2S: Context:= TDCP_blake2s.Create(nil);
HASH_BLAKE2SP: Context:= TDCP_blake2sp.Create(nil);
HASH_BLAKE2B: Context:= TDCP_blake2b.Create(nil);
HASH_BLAKE2BP: Context:= TDCP_blake2bp.Create(nil);
HASH_BLAKE3: Context:= TDCP_blake3.Create(nil);
HASH_CHECKSUM32: Context:= TDCP_checksum32.Create(nil);
HASH_CRC32: Context:= TDCP_crc32.Create(nil);
HASH_HAVAL: Context:= TDCP_haval.Create(nil);
HASH_MD4: Context:= TDCP_md4.Create(nil);
HASH_MD5: Context:= TDCP_md5.Create(nil);
HASH_RIPEMD128: Context:= TDCP_ripemd128.Create(nil);
HASH_RIPEMD160: Context:= TDCP_ripemd160.Create(nil);
HASH_SFV: Context:= TDCP_crc32.Create(nil);
HASH_SHA1: Context:= TDCP_sha1.Create(nil);
HASH_SHA224: Context:= TDCP_sha224.Create(nil);
HASH_SHA256: Context:= TDCP_sha256.Create(nil);
HASH_SHA384: Context:= TDCP_sha384.Create(nil);
HASH_SHA512: Context:= TDCP_sha512.Create(nil);
HASH_SHA3_224: Context:= TDCP_sha3_224.Create(nil);
HASH_SHA3_256: Context:= TDCP_sha3_256.Create(nil);
HASH_SHA3_384: Context:= TDCP_sha3_384.Create(nil);
HASH_SHA3_512: Context:= TDCP_sha3_512.Create(nil);
HASH_TIGER: Context:= TDCP_tiger.Create(nil);
HASH_XXH3_128: Context:= TDCP_xxh3_128.Create(nil);
end;
Context.Init;
end;
procedure HashUpdate(var Context: THashContext; const Buffer; BufLen: LongWord);
begin
Context.Update(Buffer, BufLen);
end;
procedure HashFinal(var Context: THashContext; out Hash: String);
var
I, HashSize: LongWord;
Digest: array of Byte;
begin
Hash:= EmptyStr;
HashSize:= Context.HashSize div 8;
SetLength(Digest, HashSize);
Context.Final(Pointer(Digest)^);
for I := 0 to HashSize - 1 do
Hash := Hash + HexStr(Digest[I], 2);
Hash := LowerCase(Hash);
FreeAndNil(Context);
end;
function HashString(const Line: String; IgnoreCase, IgnoreWhiteSpace: Boolean): LongWord;
var
S: String;
I, J, L: Integer;
begin
S := Line;
if IgnoreWhiteSpace then
begin
J := 1;
L := Length(Line);
for I:= 1 to L do
begin
// Skip white spaces
if not (Line[I] in [#9, #32]) then
begin
S[J] := Line[I];
Inc(J);
end;
end;
SetLength(S, J - 1);
end;
if IgnoreCase then S := UTF8LowerCase(S);
Result := crc32(0, nil, 0);
Result := crc32(Result, PByte(S), Length(S));
end;
function TrimHash(const AHash: String): String;
var
I, J: Integer;
begin
J:= 0;
Result:= EmptyStr;
SetLength(Result, Length(AHash));
for I:= 1 to Length(AHash) do
begin
if (AHash[I] in ['0'..'9', 'A'..'F', 'a'..'f']) then
begin
Inc(J);
Result[J]:= AHash[I];
end;
end;
SetLength(Result, J);
end;
function FileExtIsHash(const FileExt: String): Boolean;
var
I: THashAlgorithm;
begin
Result:= False;
for I:= Low(HashFileExt) to High(HashFileExt) do
begin
if SameText(FileExt, HashFileExt[I]) then Exit(True);
end;
end;
function FileExtToHashAlg(const FileExt: String): THashAlgorithm;
var
I: THashAlgorithm;
begin
for I:= Low(HashFileExt) to High(HashFileExt) do
begin
if SameText(FileExt, HashFileExt[I]) then Exit(I);
end;
end;
end.