Link to home
Start Free TrialLog in
Avatar of brockes
brockes

asked on

Dynamic Array of Chars to String

Hi all,

Can I copy the content of a dynamic array of chars to one string? Can StrPas work with dynamic arrays? I'm using D5.

Thanks in advance.

Beginner
Avatar of Stuart_Johnson
Stuart_Johnson

StrPas won't do it as far as I can tell, but this will:

var
  A: Array of Char;
  S: String;
  I: Integer;
begin
  SetLength(A, 4); //define length of array

  A[0] := 'B';  //assign some stuff to each element
  A[1] := 'O';
  A[2] := 'O';
  A[3] := '!';

  S := '';
  for I := 0 to high(A) do  //loop through each element
    S := S + A[I];          //and add to our string

  ShowMessage(S);
end;

HTH.

Stu
(note- there maybe a nicer way of doing this, I'm not sure).
type
  TCharArray = array of char;

function DynaToStr(dync: TCharArray): string;
begin
  Result := string(copy(dync, 0, length(dync)));
end;

or

function DynaToStr(dync: TCharArray): string;
var L: integer;
begin
  L := Length(dync);
  SetLength(Result, L);
  Move(dync[0], Result[1], L);
end;

wbr, mo.
If you always terminate the array of char with a chr(0) then StrPas will work nicely.
Avatar of brockes

ASKER

Sorry, You all are right, If I had more points I would accept the answer now, but as I only have more 5 points, I will ask one more question, who answer it takes the 55 points. I try your answers in my code but it do not work. I found that I'm trying to use an old rc4 encription component wich not accept dynamic arrays as output arrays and I need to set the output array length in function of Length(Edit1.Text). If static arrays don't accept SetLength or a var (outarray[0..L]) as argument, how can I create an array with same length of Edit1.Text in execution time? For example, if the user types 5 characters in Edit1.Text, I need to create a static array of the same size (array[0..4] of char).
You can do it by simple assignments:

procedure TForm1.Button1Click(Sender: TObject);
var
 A: Array of Char;
 S: String;
begin
 SetLength(A, 4); //define length of array

 A[0] := 'B';  //init array
 A[1] := 'O';
 A[2] := 'O';
 A[3] := '!';

 S := PChar(A); // assignments

 ShowMessage(S);
end;

Some points:

-- StrPas function will work too. But, from Delphi help:
"This function is provided for backwards compatibility only. To convert a null terminated string to a Pascal-type string, use a typecast or an assignment."

-- Using "array of char" dynamic array type is make no sense because it actually String(long).
 
-- To swift99:
Dynamic arrays and Strings (long) in delphi always ends by #0, so you not need to worry about.

-- You cannot dynamically create static array if you not defined this type before. But you can define the type big enough (for example, 65535 characters) and provide actual size as parameter:

PMyArray = ^TMyArray;
TMyArray = array[0..65535] of char;
...
MyArray : PMyArray;
...
// create array
GetMem(MyArray, Length(Edit1.Text) + 1);
Move(PChar(Edit1.Text), MyArray^, Length(Edit1.Text) + 1);





Sorry,
Last line:
Move(PChar(Edit1.Text)^, MyArray^, Length(Edit1.Text) + 1);

can you post here your encryption function declaration you call? (something like function Encrypt(what, key: string; var BufOut; bufLen: integer)
mo.
Avatar of brockes

ASKER

I am trying encript and decript a string, if the old rc4 component would accept dynamic arrays as output arrays, the following code would work, but this old rc4 component appears not implemented to work with dynamic arrays because when I try to run this code the system freezes and the hard drive light don't stop to blink.

var
  Form1: TForm1;
  RC41IVector: String;
  outarray1: array of char; //dynamic arrays
  outarray2: array of char;

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
begin
RC41 := TRC4.Create(Self);
 try
 RC41.InputType := SourceString;
 RC41.InputString := Edit1.Text;
 SetLength(outarray1, Length(Edit1.Text));
 RC41.pOutputArray := @outarray1;
 RC41.Key := 'abcdefghijklmnop';
 RC41.CipherMode := ECBMode;
 RC41.EncipherData(False);
 RC41IVector := RC41.IVector;
 Edit2.Text := StrPas(outarray1);
 finally
 RC41.free;
 end;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
outarray: array of Char;
begin
RC41 := TRC4.Create(Self);
 try
 RC41.InputType := SourceString;
 RC41.InputString := Edit2.Text;
 RC41.pOutputArray := @outarray2;
 RC41.Key := 'abcdefghijklmnop';
 RC41.CipherMode := ECBMode;
 RC41.IVector := RC41IVector;
 RC41.DecipherData(False);
 Edit2.Text := StrPas(outarray2);
 finally
 RC41.free;
 end;
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
Edit2.Text := '';
Edit3.Text := '';
Edit1.SetFocus;
Edit1.SelectAll;
end;

I will try Slavak's comment on this code, I thinking that it will work.
Avatar of brockes

ASKER

I would try Slavak's comment, it compiles, but when I try to encript one string the program hangs showing an error in the line below with the comment: 'ERROR HERE!' Please Slavak, help me to close this question.

type
POutputArray = ^TOutputArray;
TOutputArray = array[0..65535] of Char;

var
  Form1: TForm1;
  RC41IVector: String;
  outarray1, outarray2: POutputArray;

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
var
i: Integer;
begin
GetMem(outarray1, Length(Edit1.Text) + 1);
//Move(PChar(Edit1.Text), outarray1^, Length(Edit1.Text) + 1);
RC41 := TRC4.Create(Self);
 try
 RC41.InputType := SourceString;
 RC41.InputString := Edit1.Text;
 RC41.pOutputArray := @outarray1;
 RC41.Key := 'abcdefghijklmnop';
 RC41.CipherMode := ECBMode;
 RC41.EncipherData(False);
 RC41IVector := RC41.IVector;
 Edit2.Text := '';
  for i := 1 to Length(Edit1.Text) do
  begin
  Edit2.Text := Edit2.Text + outarray1[i]; //ERROR HERE!
  end;
 finally
 RC41.free;
 end;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
i: Integer;
begin
GetMem(outarray2, Length(Edit2.Text) + 1);
//Move(PChar(Edit2.Text), outarray2^, Length(Edit2.Text) + 1);
RC41 := TRC4.Create(Self);
 try
 RC41.InputType := SourceString;
 RC41.InputString := Edit2.Text;
 RC41.pOutputArray := @outarray2;
 RC41.Key := 'abcdefghijklmnop';
 RC41.CipherMode := ECBMode;
 RC41.IVector := RC41IVector;
 RC41.DecipherData(False);
 Edit3.Text := '';
  for i := 1 to Length(Edit2.Text) - 1 do
  begin
  Edit3.Text := Edit3.Text + outarray2[i];
  end;
 finally
 RC41.free;
 end;
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
Edit2.Text := '';
Edit3.Text := '';
Edit1.SetFocus;
Edit1.SelectAll;
end;
Hi, brockes.

I don't know what TRC4 class does, but some points.

You allocate memory for output steam at same size as input:

GetMem(outarray1, Length(Edit1.Text) + 1);

If it true (input size = output size), then may be you should place #0 char at end of allocated memory:

outarray1^[Length(Edit1.Text)] := #0;

Usually, I prefer to init allocated memory :

FillChar(OutArray1^, Length(Edit1.Text) + 1, 0);

Now, outarray1 declared as POutputArray (pointer to array of char). So, it is error to reference to address of this variable (@outputarray1). I suppose that you compile your project with disabled "Range checking" compiler option. I recomend you always enable "checking" compiler options in development phase (I prefer to remain it enable even in non performance critical parts of release version).

I cannot compile your code without TRC4 class, but it should look like this:

procedure TForm1.Button1Click(Sender: TObject);
var
i: Integer;
begin
GetMem(outarray1, Length(Edit1.Text) + 1);
FillChar(outarray1^, Length(Edit1.Text) + 1, 0); // <-- change

RC41 := TRC4.Create(Self);
try
RC41.InputType := SourceString;
RC41.InputString := Edit1.Text;
RC41.pOutputArray := outarray1; // <-- change
RC41.Key := 'abcdefghijklmnop';
RC41.CipherMode := ECBMode;
RC41.EncipherData(False);
RC41IVector := RC41.IVector;

Edit2.Text := outarray1^; // <-- change

finally
RC41.free;
end;
end;



 







You should know size of output steam.
Avatar of brockes

ASKER

Slavak,

TRC4 is an old encription component. Check next comment to see source code.

I try your last suggestion but it do not compiles due an error in the following line:

RC41.pOutputArray := outarray1; // <-- change

[Error] message is:
[Error] RC4Main.pas(51): Incompatible types: 'TOutputArray' and 'BArray'



Avatar of brockes

ASKER

unit Rc4unit;
{*****************************************************************************
 UNIT: TRC5Unit
 Description:  This unit contains an Object Pascal Object which can be used to
               perform TRC4 ciphers. 'RC4' is a trademark of RSA security
               corporation, this code is an implementation of the algorithm which
               RSA referers to as 'RC4'. TRC4 is a stream cipher, it is slightly
               different from the other ciphers included in this library.
               In 16bit code it is the fastest of the encryption algorithms.
               RSA has NOT made RC4 public, this is an implementation of the
               'rumored' algorithm.  It is only included here incase RSA
               decides to make RC4 public.  DO NOT use it, unless you have
               authorization from RSA.

               For more information on the algorithm see 'Applied Cryptography',
               Bruce Snheier or visit RSA's www page.  http://www.rsa.com

 The RC4 Algorithm was produced by Ronald Rivest.(See LEGAL)
 -----------------------------------------------------------------------------
 Code Author:  Greg Carter, gregc@cryptocard.com
 Organization: CRYPTOCard Corporation, info@cryptocard.com
               R&D Division, Carleton Place, ON, CANADA, K7C 3T2
               1-613-253-3152 Voice, 1-613-253-4685 Fax.
 Date of V.1:  Jan. 3 1996.

 Compatibility & Testing with BP7.0: Anne Marcel Roorda, garfield@xs4all.nl
 -----------------------------------------------------------------------------}
 {Useage:  Below is typical usage(for File)of the TRC4 Object,
           Follow these steps:
           1) Declare and Create Variable of type TRC4.
           2) Set InputSource Type, either SourceFile, SourceByteArray, or
              SourceString(Pascal style string).
           3) Point to Input Source and set Input Length(If needed)
           4) Point to Output Structure(array, file).
           5) Set Key;
           6) Call BF_EncipherData Method.
           7) Reference the Output. Thats it.
 **** Note **** Steps 2..6 can occure in any order.
 Here is a procedure in Delphi used to encrypt a file:
procedure Tcryptfrm.OpenCiphButtonClick(Sender: TObject);
var
 RC4: TRC4; (*Step 1*)
begin
RC4 := TRC4.Create;(*Step 1b*)
 try
  If OpenDialog1.Execute then
  begin
   RC4.InputType := SourceFile; (*Step 2*)
   RC4.InputFilePath := OpenDialog1.FileName; (*Step 3*)
   RC4.OutputFilePath := ChangeFileExt(OpenDialog1.FileName, '.ccc'); (*Step 4*)
   RC4.Key := 'abcdefghijklmnopqrstuvwxyz'; (*Step 5*)
   RC4.BF_EncipherData(False);  (*Step 6*)
  end;
 finally
  RC4.free;
 end;
end;

{-----------------------------------------------------------------------------}
{LEGAL:        The algorithm is in the process of being patented, and its name
               'RC4' is trademarked.  Please oontact RSA Data Security for
               licensing arrangements. This code is copyright by
               CRYPTOCard.  CRYPTOCard grants anyone who may wish to use, modify
               or redistribute this code privileges to do so, provided the user
               agrees to the following three(3) rules:

               1)Any Applications, (ie exes which make use of this
               Object...), for-profit or non-profit,
               must acknowledge the author of this Object(ie.
               TRC4 Implementation provided by Greg Carter, CRYPTOCard
               Corporation) somewhere in the accompanying Application
               documentation(ie AboutBox, HelpFile, readme...).  NO runtime
               or licensing fees are required!

               2)Any Developer Component(ie Delphi Component, Visual Basic VBX,
               DLL) derived from this software must acknowledge that it is
               derived from "TRC4 Object Pascal Implementation Originated by
               Greg Carter, CRYPTOCard Corporation 1996". Also all efforts should
               be made to point out any changes from the original.
               !!!!!Further, any Developer Components based on this code
               *MAY NOT* be sold for profit.  This Object was placed into the
               public domain, and therefore any derived components should
               also.!!!!!

               3)CRYPTOCard Corporation makes no representations concerning this
               software or the suitability of this software for any particular
               purpose. It is provided "as is" without express or implied
               warranty of any kind. CRYPTOCard accepts no liability from any
               loss or damage as a result of using this software.

CRYPTOCard Corporation is in no way affiliated with RSA Data Security Inc.
The RC4 Algorithm was produced by Ronald Rivest.
-----------------------------------------------------------------------------
Why Use this instead of a freely available C DLL?

The goal was to provide a number of Encryption/Hash implementations in Object
Pascal, so that the Pascal Developer has considerably more freedom.  These
Implementations are geared toward the PC(Intel) Microsoft Windows developer,
who will be using Borland's New 32bit developement environment(Delphi32).  The
code generated by this new compiler is considerablely faster then 16bit versions.
And should provide the Developer with faster implementations then those using
C DLLs.
-----------------------------------------------------------------------------
NOTES: Make sure to read the LEGAL notes.
------------------------------------------------------------------------------
Revised:  00/00/00 BY: ******* Reason: ******
------------------------------------------------------------------------------
}
interface
{Declare the compiler defines}
{$I CRYPTDEF.INC}
{------Changeable compiler switches-----------------------------------}
{$A+   Word align variables }
{$F+   Force Far calls }
{$K+   Use smart callbacks
{$N+   Allow coprocessor instructions }
{$P+   Open parameters enabled }
{$S+   Stack checking }
{$T-   @ operator is NOT typed }
{$IFDEF DELPHI}
{$U-   Non Pentium safe FDIV }
{$Z-   No automatic word-sized enumerations}
{$ENDIF}
{---------------------------------------------------------------------}
{.$DEFINE TEST}
uses SysUtils, Cryptcon{$IFDEF DELPHI}, Classes, Controls{$ENDIF}
     {$IFDEF BP7},objects{$ENDIF};

type
{$IFDEF DELPHI}
 TRC4 = class(TCrypto)
{$ENDIF}
{$IFDEF BP7}
 PRC4 = ^TRC4;   {For BP7 Objects}
 TRC4 = object(TCrypto)
{$ENDIF}
 Private
  {RC4 Key Elements}
  FState: Array[0..255] of BYTE;
  FI: BYTE;
  FJ: BYTE;
 {$IFDEF DELPHI}
  Procedure SetKeys;       override; {Sets up En\DecipherKey SubKeys}
  Procedure Encipher_Bytes;override;
  Procedure Decipher_Bytes;override;
{$ENDIF}
{$IFDEF BP7}
  Procedure Encipher_Bytes; virtual;
  Procedure Decipher_Bytes; virtual;
  Procedure SetKeys;        virtual; {Sets up En\DecipherKey SubKeys}
{$ENDIF}
 public
    { Public declarations }
{$IFDEF DELPHI}
  constructor Create(Owner: TComponent);override;
{$ENDIF}
{$IFDEF BP7}
  constructor Init;
{$ENDIF}
end;{TRC4}

{$IFDEF DELPHI}
 procedure Register;{register the component to the Delphi toolbar}
{$ENDIF}

implementation

{$IFDEF DELPHI}
procedure Register;
  {Registers the Component to the toobar, on the tab named 'Crypto'}
  {Now all a Delphi programmer needs to do is drag n drop to have
   Blowfish encryption}
begin
  RegisterComponents('Crypto', [TRC4]);
end;
{$ENDIF}

{==================================TRC4========================================}

{$IFDEF DELPHI}
constructor TRC4.Create(Owner: TComponent);
{$ENDIF}
{$IFDEF BP7}
constructor TRC4.Init;
{$ENDIF}
begin
{ Decipher_Bytes := @Encipher_Bytes;}
{$IFDEF DELPHI}
  inherited Create(Owner);
{$ENDIF}
end;

Procedure TRC4.SetKeys;
{------------------------------------------------------------------------------
 Initializing the S-Box.  First fill it linearly: So=0, S1=1...S255=255.
 Then fill another 256byte array with the key, repeating the key as necessary
 to fill the entire array: K0, K1..K255.
 Then
 j=0
 for i=0 to 255
  j = (j + Si + Ki) mod 256
  swap Si and Sj
-------------------------------------------------------------------------------}
var
 KeyLen, j: WORD; i, swapbyte: BYTE;
 K: Array[0..255] of BYTE;

begin
 KeyLen := Length(FKey);
 FI := 0; FJ := 0;j := 0;
 for i:= 0 to 255 do begin
  FState[i] := i; K[i] := BYTE(FKey[(i MOD KeyLen) + 1]);
 end;
 for i := 0 to 255 do begin
  j := (j + FState[i] + K[i]) MOD 256;
  swapbyte := FState[i]; FState[i] := FState[j]; FState[j] := swapbyte;
 end;
end;{SetKeys}

Procedure TRC4.Encipher_Bytes;
{------------------------------------------------------------------------------
 i=j=0

 i=(i + 1) mod 256
 j=(j + Si) mod 256
 swap Si and Sj
 t = (Si + Sj) mod 256
 K = St

 the BYTE K is XOR withe plaintext to produce ciphertext or XORED with
 the ciphertext to produce plaintext

 We assume that the data to encipher is in FBuffer, and FInputLength holds the
 length of FBuffer.
 ------------------------------------------------------------------------------}
 var
  i, j, t, swapbyte: BYTE;
  x: WORD;
 begin
  i:= FI; j:= FJ;

  For x := 0 to (FInputLength - 1) do begin
   i := (i + 1) MOD 256;
   j := (j + FState[i]) MOD 256;
   swapbyte := FState[i]; FState[i] := FState[j]; FState[j] := swapbyte;
   t := (FState[i] + FState[j]) MOD 256;
   FOutputArray^[x] := FState[t] Xor FBuffer[x];
  end;

  FI := i;
  FJ := j;
 end;

Procedure TRC4.Decipher_Bytes;
begin
 Encipher_Bytes;
end;
end.
ASKER CERTIFIED SOLUTION
Avatar of Slavak
Slavak

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
Avatar of brockes

ASKER

The old encription component that I was using is: http://www.torry.net/vcl/security/strong/cryptov1.zip
Sorry to waste your time Slavak. However I get to solve this question, look the code below, it works! But I should recognize that you helps a lot. I will give you the points. Thank you.

unit BlowFishM;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, Cryptcon, Ideaunit, Blowunit, HKSafeForm;

type
  TForm1 = class(TForm)
    Edit2: TEdit;
    Edit3: TEdit;
    Edit1: TEdit;
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    HKSafeForm1: THKSafeForm;
    BlowFish1: TBlowFish;
    procedure Button1Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  outarray1, outarray2: array[0..255] of Char;
  BFIVector: String;

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
var
BlowFish: TBlowFish;
begin
BlowFish := TBlowFish.Create(Self);
 try
 BlowFish.InputType := SourceString;
 BlowFish.InputLength := Length(Edit1.Text);
 BlowFish.InputString := Edit1.Text;
 BlowFish.Key := 'abcdefghijklmnopqrstuvwxyz';
 BlowFish.CipherMode := ECBMode;
 FillChar(outarray1, 255, #0);
 BlowFish.pOutputArray := @outarray1;
 BlowFish.EncipherData(False);
 BFIVector := BlowFish.IVector;
 Edit2.Text := StrPas(outarray1);
 finally
 BlowFish.free;
 end;
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
Edit2.Text := '';
Edit3.Text := '';
Edit1.SetFocus;
Edit1.SelectAll;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
BlowFish: TBlowFish;
begin
BlowFish := TBlowFish.Create(Self);
 try
 BlowFish.InputType := SourceByteArray;
 BlowFish.InputLength := Length(Edit2.Text);
 BlowFish.pInputArray := @outarray1;
 BlowFish.Key := 'abcdefghijklmnopqrstuvwxyz';
 BlowFish.CipherMode := ECBMode;
 FillChar(outarray2, 255, #0);
 BlowFish.pOutputArray := @outarray2;
 BlowFish.IVector := BFIVector;
 BlowFish.DecipherData(False);
 Edit3.Text := StrPas(outarray2);
 finally
 BlowFish.free;
 end;
end;

end.
Avatar of brockes

ASKER

You answer do not solve the question, but help me to solve it, thanks.