Please help me convert C code from this:

Please help me convert C code from this:

const ULONG length = MOV_make_string2(tdbb, value, value->getTextType(), &address, buffer, false);

for (const UCHAR* end = address + length; address < end; ++address)
{
impure->vlu_misc.vlu_int64 = (impure->vlu_misc.vlu_int64 << 4) + *address;

const SINT64 n = impure->vlu_misc.vlu_int64 & CONST64(0xF000000000000000);
if (n)
impure->vlu_misc.vlu_int64 ^= n >> 56;
impure->vlu_misc.vlu_int64 &= ~n;
}

where vlu_int64 is SINT64, address is UCHAR*.

This is C implementation of HASH function from Firebird.

My implementation "almost" works:

var
s : AnsiString;
b : Byte;
h : Int64; //result hash
n : Int64;
i : Integer;
begin
h := 0;
s := trim(mmo1.text);
for i := 1 to Length(s) do
begin
b := Byte(s[i]);
h := Int64(h shl 4)) + b;
n := Int64(h and Int64($F000000000000000));
if n > 0 then
begin
h := Int64(h xor Int64(n shr 56)));
end;
h := Int64(h and Int64(not n));
end;
end;

For short string result is compatible with FB hash, but when h value is big then result is bad.
What I'm doing wrong?

Comments

  1. if (n) means if n <> 0

    either inline asm and use sar or div 2^56

    ReplyDelete
  2. I change code to:

    for i := 1 to Length(s) do
    begin
    b := Byte(s[i]);
    h := Int64((Int64(h) shl 4) + b);
    n := Int64(Int64(h) and Int64($F000000000000000));
    if n <> 0 then
    begin
    h := Int64(Int64(h) xor (h div Int64(Int64(2) shl 56)));
    end;
    h := Int64(h and Int64(not Int64(n)));
    end;

    ...but I still get incorrect result on long strings.

    ReplyDelete
  3. this code works properly:

    for i := 1 to Length(s) do
    begin
    b := Byte(s[i]);
    h := Int64((Int64(h) shl 4) + b);
    n := Int64(Int64(h) and Int64($F000000000000000));
    if n <> 0 then
    begin
    h := Int64(Int64(h) xor ((n shr 56) or ((0 - ((n shr 63) and 1)) shl 8)));
    end;
    h := Int64(h and Int64(not Int64(n)));
    end;

    ReplyDelete

Post a Comment