Solved

# Converting a function from C to Delphi

Posted on 1998-12-01
Medium Priority
334 Views
Last Modified: 2010-04-04
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.
0
Question by:delphiexpert
• 7
• 6
• 5
• +4
25 Comments

LVL 12

Expert Comment

ID: 1348845
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.
0

LVL 3

Expert Comment

ID: 1348846
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.
0

LVL 1

Author Comment

ID: 1348847
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.

0

LVL 1

Author Comment

ID: 1348848
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.

0

LVL 3

Expert Comment

ID: 1348849
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
0

LVL 1

Author Comment

ID: 1348850
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.
0

LVL 3

Expert Comment

ID: 1348851
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
0

LVL 1

Author Comment

ID: 1348852
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!
0

LVL 10

Expert Comment

ID: 1348853
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
0

LVL 10

Expert Comment

ID: 1348854
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
0

Accepted Solution

bdtikast earned 400 total points
ID: 1348855
I have made this and it gives your suggested result.

const
sEnc: string = #206#99#209#210#22#231#19#207; //*!*QWTY? ,
lSeed: integer = 31337;
holdrand: integer = 1;

procedure msrand (seed: dword);
begin
holdrand:= seed;
end;

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

procedure TForm1.Button1Click(Sender: TObject);
var
y: integer;
s: string;
begin
msrand(lseed);
s:= '';
for y:= 1 to length(sEnc)
do begin
s:= s+chr(ord(sEnc[y]) xor (mrand and 255));
end;
Edit1.Text:= s;
end;

0

LVL 10

Expert Comment

ID: 1348856
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
0

LVL 3

Expert Comment

ID: 1348857
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.
0

LVL 10

Expert Comment

ID: 1348858
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
0

LVL 10

Expert Comment

ID: 1348859
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
0

LVL 3

Expert Comment

ID: 1348860
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
0

LVL 10

Expert Comment

ID: 1348861
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
0

LVL 3

Expert Comment

ID: 1348862
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
0

LVL 12

Expert Comment

ID: 1348863
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.
0

LVL 10

Expert Comment

ID: 1348864
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
0

LVL 3

Expert Comment

ID: 1348865
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
0

LVL 3

Expert Comment

ID: 1348866
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.

0

LVL 1

Author Comment

ID: 1348867
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!

0

Expert Comment

ID: 1348868
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)
0

LVL 3

Expert Comment

ID: 1348869
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
0

## Featured Post

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

## Join & Write a Comment Already a member? Login.

Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
Free Data Recovery software is an advanced solution from Kernel Tools to recover data and files such as documents, emails, database, media and pictures, etc. It supports recovery from physical & logical drive after a hard disk crash, accidental/inte…
When you have multiple client accounts to manage, it often feels like there aren’t enough hours in the day. With too many applications to juggle, you can’t focus on your clients, much less your growing to-do list. But that doesn’t have to be the cas…
###### Suggested Courses
Course of the Month5 days, 18 hours left to enroll

#### 569 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.