Solved

Converting a function from C to Delphi

Posted on 1998-12-01
25
318 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
Comment Utility
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
Comment Utility
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
Comment Utility
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

by:delphiexpert
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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 100 total points
Comment Utility
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
Comment Utility
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
Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

 
LVL 3

Expert Comment

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

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Suggested Solutions

Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
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…
It is a freely distributed piece of software for such tasks as photo retouching, image composition and image authoring. It works on many operating systems, in many languages.
Illustrator's Shape Builder tool will let you combine shapes visually and interactively. This video shows the Mac version, but the tool works the same way in Windows. To follow along with this video, you can draw your own shapes or download the file…

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

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now