Link to home
Start Free TrialLog in
Avatar of delphiexpert
delphiexpert

asked on

Converting a function from C to Delphi

I'm curently in the process of writing a BO packet detector but I've been unable to get the BO "random" number generator to convert from the C code to delphi.

The C code (as in the source for the BO client for unix) is as follows:

int mrand ( void)
{
  return(((holdrand = holdrand * 214013L + 2531011L) >> 16) & 0x7fff);
}

my translation goes like this:

function mrand(x:integer);
begin
     result:=(((x * 214013) + 2531011) shr 16) and $7fff;
end;

the problem is, this doesn't always return the same results as the C version.  I've tried everything I can think of.. can anyone help?
Thanks.
Avatar of rwilson032697
rwilson032697

Try this:

function mrand(x:integer):integer;
    begin
         result:=(Longint(((x * 214013) + 2531011)) shr 16) and $7fff;
    end;

BTW: What is the type of HoldRand? If it is a unsigned 32 bit int then x should be cast as a LongWord (assuming D4).

If this doesn't work then I guess there is some difference in how the overflow bits are dealt with between the C and Delphi compilers...

Cheers,

Raymond.
The way you've implemented it, it means that you must always pass the last return value to the function each time you call it.
Why not do it the way it is done in c.
Presumably holdrand is declared like:
static int holdrand = 0;

Why not have code like this:
const holdrand: Integer = 0;

function mrand: Integer;
  begin
     holdrand := ... //your calculation
     Result := holdrand;
  end;

Hope this helps,
Phil.

PS: You're not using Delphi 1 right? If so, use LongInts.
Avatar of delphiexpert

ASKER

That didn't work I'm afraid.  I'm using Delphi 3 so I can't use a LongWord.  As you said, I'm sure it's something to do with the difference in handling overflows but I've tried every type of variable I can think of and nothing works.  Is there a LongWord equivalent for D3?
Here's the definition of holdrand by the way:
static long holdrand = 1L;

philip,
the reason I implemented it the way I did is because it saved using a global variable unneccessarily, I did however try it your way but that didn't work either.

That didn't work I'm afraid.  I'm using Delphi 3 so I can't use a LongWord.  As you said, I'm sure it's something to do with the difference in handling overflows but I've tried every type of variable I can think of and nothing works.  Is there a LongWord equivalent for D3?
Here's the definition of holdrand by the way:
static long holdrand = 1L;

philip,
the reason I implemented it the way I did is because it saved using a global variable unneccessarily, I did however try it your way but that didn't work either.

Ok, here it comes I guess.. I mean, I hope so :-)

In fact this is THE way to handle Longwords in Delphi, if you need help with further assembling, you may say so.

If this doesn't work, you better check your compiler :-))

function mrand(x: LongInt): LongInt; Register;
begin
  asm
    Mov  eax,x
    Imul eax,214013
    Add  eax,2531011
    Shr  eax,16
    And  eax,$7fff
    Mov  result,eax
  end;
end;

Regards
Williams
Ok.. maybe I'm doing something wrong.  
Some more info:
The full source of the unix client is available at http://www.cultdeadcow.com/tools/
Basic protocol specs including pseudo code to encrypt/decrypt is also available at http://web.cip.com.br/flaviovs/boproto.html
The encryption/decryption uses xor and as far as I'm aware, its exactly the same both ways.

The encrypted header is #206#99#209#210#22#231#19#207, and this should decrypt to the BO header of  *!*QWTY? - the random seed is 31337.

My translation of the decryption routine:
procedure Decrypt(var st:array[0..7] of char);
var l,z,x:testtype;
begin
     l:=sizeof(st);
     x:=0;
     z:=randomseed; //31337
     while x<l do
     begin
          z:=mrand(z);
          st[x]:=char(ord(st[x]) xor z);
          inc(x);
     end;
end;

If anyone can get #206#99#209#210#22#231#19#207 to decrypt to *!*QWTY? , i'd like to know about it.  The only thing I can think of is that I've got the encrypted string wrong, but I captured it from a request sent by the genuine BO client. For me it only decrypts the first character correctly, the rest don't work.
This really is worth more than the points I've given it, but that's every last point I have.
Try this is should work tried it out myself comparing results from C and delphi

function mrand ( x : longint ) : longint;
begin
   result :=  (longint(x * 214013 + 2531011) shr 16) and $00007fff
end;

regards,

Cono
OK, if that code produces the same results as it does in C then the problem must lie elsewhere

here are the appropriate sections of code in C:

static long holdrand = 1L;

void  msrand (unsigned int seed )
{
  holdrand = (long)seed;
}

int mrand ( void)
{
  return(((holdrand = holdrand * 214013L + 2531011L) >> 16) & 0x7fff);
}

void BOcrypt(unsigned char *buff, int len)
{
  int y;
 
  if (!len)
    return;
 
  msrand(getkey());
  for (y = 0; y < len; y++)
    buff[y] = buff[y] ^ (mrand()%256);
}

assuming that getkey() always returns 31337 (its the default if no password is used)

My translation is above, can anyone see where it's gone wrong?  I've spent waaaaay too much time on this already.  Thanks!
in C
int mrand ( void)
   {
     return(((holdrand = holdrand * 214013L + 2531011L) >> 16) & 0x7fff);
   }
in Delphi(pascal)

function mrand : integer;
begin
  result := ((holdrand * LongInt(214013) + LongInt(2531011)) shr 16) and $7fff;
end;

try it out and tell me how it goes...

Cheers,
Viktor
Actually wait...  YOu change the value of holdrand. Then it should be like this..

in Delphi(pascal)

     function mrand : integer;
     begin
       holdrand := ((holdrand * LongInt(214013) + LongInt(2531011)) shr 16) and $7fff;
       result := holdrand;
     end;

Try it out and tell me how it works./ k??

Cheers,
Viktor
ASKER CERTIFIED SOLUTION
Avatar of bdtikast
bdtikast

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Opsssss.....

bdtikast- There is no way that thing to work since you've made holdrand to be a CONSTANT

const
     holdrand: integer = 1;

and then you try to assign a value to that CONSTANT

   procedure msrand (seed: dword);
   begin
     holdrand:= seed; //You try to assign the value to a CONST variable
   end;

I don't evem think that this code would compile.. How did you get it to compile???

Cheers,
Viktor
The truth is sometimes a hard to swallow Viktor, but bdtikast is right about the mrand function. If he came just 15 minutes later, I would have proposed the answer, so I'll do that any way:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  holdrand: LongInt;

implementation

{$R *.DFM}

Procedure msrand(seed: Integer);
Begin
  holdrand := LongInt(seed);
End;

Function mrand: LongInt;
Begin
  asm
    Mov  eax,holdrand
    Imul eax,214013
    Add  eax,2531011
    mov  holdrand,eax
    Shr  eax,16
    And  eax,$7fff
    mov  result,eax
  end;
end;

Procedure BOcrypt(var buff: String);
var
  y: Integer;
Begin
  if length(buff)=0 then exit;
  msrand(31337);
  for y := 1 to length(buff) do
    buff[y] := Chr(Ord(buff[y]) xor (mrand AND 255));
End;

procedure TForm1.FormCreate(Sender: TObject);
var
  S: String;
begin
  S:= #206#99#209#210#22#231#19#207;
  BOcrypt(S);
  ShowMessage(S);
end;

Initialization
  holdrand:= 1;
end.
Oppps....

Sorry... Forget what i said.. I don't know why it compiles, but it actually does... shoot me in the head... i deserve it :)

as a matter of fact it gives the exact results that you want..

Cheers,
Viktor
willie... I wasn't sure about the constant...why it compiles as you try changing the value of the holdrand constant... Why is it called a constant then??? if you can change its value?? answer this question...

Cheers,
Viktor
You are absolutely right Viktor, "DelphiExpert" can NOT compile the proposed answer from bdtikast, because of this.
If you take a look at my answer to all this, I didn't use a contant either. But I was talking of the principe. If you take a look at this:

function mrand: integer;
begin
  holdrand:= holdrand * 214013 + 2531011;
  result:= (holdrand shr 16) and $7fff;
end;

This would do, if though the holdrand is var declared, but it basically works exactly like mine:

Function mrand: LongInt;
Begin
  asm
    Mov  eax,holdrand
    Imul eax,214013
    Add  eax,2531011
    mov  holdrand,eax
    Shr  eax,16
    And  eax,$7fff
    mov  result,eax
  end;
end;


But you may put the question if he deserves the credits?, though I'm not in a position to judge this. I agree with you, that a codeexample should be compiled before reveiling it to the public.. :-/

/Williams
Williams... Are you making fun of me or have the same opinion as me??? I can't understand that.. If it's a constant it should not be able to change throught the program.. It should give an error and should not compile... What's your opinion Williams?? I think your example Williams is better than the other persons... YOu actually used some Asm which is pretty good even though it's not needed, but anyway... And you didn't make it a constant and load it in the Initialization part of the program.. I think your example is better... Anyway, please tell me Williams if oyu were trying to support me on that or are just making fun of me...

Cheers,
Viktor
No dear Viktor, I'm surdently not making fun of you! I'm trying not to be too disappointed with the proposal, because he was really close on solving the problem.

I really do agree with you Viktor, because bdtikast was very careless not trying to compile his project before proposing it as an answer, he should instead propose how he identifies the problem.

In this perspective his answer is wrong and should therefore be rejected!

Cheers,
Williams
Hi Guys,

Typed constants (which is what constant declarations you can change are called) were the way Borland allowed you to do automatic initialisation. True, calling them constants is a little naughty, though there is a compiler directive to disallow changing the values of these.

Cheers,

Raymond.
I hate Borland's little games.... If it is a constant it should be one and not be able to change.... I think when I had D3 i couldn't change a constant... now that I've never tried it with D4 (till 5 hours ago) I thought it was the same... I don't think assembler code is needed just to confuse things...

Cheers,
Viktor
Hmmm... I tried D4 once, and that's the last time I'll try it again. Actually it's so buggy, that Borland has allready started on building D5!

maybe you should mention, that there are 5 kinds of typed contants in C++, and they are all practical, like GOTO! ..and I cannot share my opinion about that, because the language then would be way too filthy. :-)

Cheers,
Williams
I really wonder sometimes about the whole expert thing.

1. bdtikast's answer compiles without modification, and gives the exact same answer as requested.
2. Just because it's assembler, that doesn't make it better, just harder to maintain.
3. Typed constants have been around since Delphi 1, and no, it's not a compiler bug.
4. To delphiexpert, a module-global is less overhead than passing an arg to a function over and over again.

In essence, the original problem stems from misinterpreting the position of the brackets. holdrand does not get assigned the entire expression, only the first half. Have a close look at the proposed answer. It deserves an A.

OK, well while everyone was busy discussing the answer to this, I found some code that worked on my own (there's no point posting it seeing as its no better than the answers given here).  But seeing as bdikast's answer works and he posted it first, I'm going to give him the points.. hopefully no-one has an objection to that.  I wish you could distribute the points amongst more than 1 person as you've all helped a lot.
Thanks!

Thnx delphiexpert your most generous, my first points.
To victornet and williams, yes constant has been around for long times in delphi. I think of this, as variables with initial value. I tried to be honnest to the revealed C code as the issue was "Converting a function from C to delphi".
I only wanted the represent a solution as clear as possible. To use asm, I agree is a way to make it fast. I seldom use this in the first prototype of an application, because from a running prototype I have a foundation to make the justment if the code need a brush-up in speed.
Thnx for commenting though some was hard. (I did compile, and checked the result)
No offence dear bdtikast. Contgratulations to your well earned points!

I've never used typed constants in Delphi, I didn't make it to compile, but nevertheless I didn't know the option to use it in Delphi.
Anyway, I do code a lot in C, and I must admit, that the C source at www.CultOfTheDeadCow.com is poorly written.
In my opinion, the fault is the typology of the C-languages. This is also the exact reason why I chose Delphi as my main programming language at all.

Cheers everybody, and have a nice day, this discussion has been fun.

/Williams