Fabrice76
Fabrice76

Reputation: 63

Delphi ELF-32 hash algorithm conversion to C#

I've got a Delphi function to convert into C#. I found C# ELF-32 examples and it seems to work as in Delphi, but i've got doubts with the returned type...

Here's is the Delphi functions/procedure (the result is in Digest, Buf is the string to hash...) :

Type
 TByteArray = array[0..32767] of Byte;

procedure HashELF(var Digest : LongInt; const Buf;  BufSize : LongInt);
var
  I, X  : LongInt;
begin
  Digest := 0;
  for I := 0 to BufSize - 1 do begin
    Digest := (Digest shl 4) + TByteArray(Buf)[I];                   {!!.01}
    X := Digest and $F0000000;
    if (X <> 0) then
      Digest := Digest xor (X shr 24);
    Digest := Digest and (not X);
  end;
end;

procedure StringHashELF(var Digest : LongInt; const Str : string);
begin
  HashELF(Digest, Str[1], Length(Str));
end;

function MyHashELF(buffer : string): LongInt;
var
    ELFDigest : LongInt;
begin
     StringHashELF(ELFDigest, buffer);
     result := ELFDigest;
end;

The "return value" is type LONGINT (–2147483648 to 2147483647)

I found some equivalent on the net in C#

private static UInt32 MyHashELF(string buffer)
{
    UInt32 hash = 0;
    for (int i = 0; i < buffer.Length; i++)
    {
        hash = (hash << 4) + (byte)buffer[i];
        UInt32 work = (hash & 0xf0000000);
        if (work != 0)
            hash ^= (work >> 24);
        hash &= ~work;
    }
    return hash;
}

But the return type is Uint32 (0 to 4294967295) and if I want to change Uint32 in Int32, I've got the following error (on 0xf0000000) :

Constant value '4026531840' cannot be converted to a 'int' (use 'unchecked' syntax to override)

I've made some tests and for the moment it works all the time as same as Delphi but I think there may be potentially errors due to the type difference (no ?). What have I got to do to be 100% compatible with the Delphi code ?

P.S. I need to use these 4 bytes returned AS IS as a part of a string (a sort of keys) in further treatment...

Thanks

Upvotes: 0

Views: 290

Answers (1)

M-Peror
M-Peror

Reputation: 842

The 4 byte result will be the same. The difference between Delphi longint and C# UInt32 is how it interprets those 4 bytes: as if it were a signed (longint) or unsigned (UInt32) integer value.

So if you really just need those 4 bytes underlying the variable verbatim, you can use the C# code as it is right now.

If you store these 4 bytes in their numerical representation somewhere, then you will have to change the C# implementation a bit, to make it compatible with the numerical value that would have been returned by the Delphi function. The C# compiler prefers unsigned values for constants represented in hex, so you will need to tell it it should treat it as signed. Just do as the compiler suggests (add unchecked to override). Change the line to:

Int32 work = (hash & unchecked((Int32)0xf0000000));

(and of course all the other UInt32 occurrences should be changed to Int32). That should work.

Upvotes: 1

Related Questions