Go Premium for a chance to win a PS4. Enter to Win

x
?
Solved

Converting a function from C to Delphi

Posted on 1998-12-01
25
Medium Priority
?
328 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
Comment
Question by:delphiexpert
  • 7
  • 6
  • 5
  • +4
25 Comments
 
LVL 12

Expert Comment

by:rwilson032697
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

by:philipleighs
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

by:delphiexpert
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
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 1

Author Comment

by:delphiexpert
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

by:williams2
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

by:delphiexpert
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

by:Ronald Buster
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

by:delphiexpert
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

by:viktornet
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

by:viktornet
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

by:
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

by:viktornet
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

by:williams2
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

by:viktornet
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

by:viktornet
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

by:williams2
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

by:viktornet
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

by:williams2
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

by:rwilson032697
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

by:viktornet
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

by:williams2
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

by:philipleighs
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

by:delphiexpert
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

by:bdtikast
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

by:williams2
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

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
Integration Management Part 2
We’ve all felt that sense of false security before—locking down external access to a database or component and feeling like we’ve done all we need to do to secure company data. But that feeling is fleeting. Attacks these days can happen in many w…

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

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

Join & Ask a Question