Solved

# Dynamic Array of Chars to String

Posted on 2003-03-05
Medium Priority
859 Views
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.

Beginner
0
Question by:brockes
[X]
###### Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

• Help others & share knowledge
• Earn cash & points
• 7
• 4
• 2
• +2

LVL 6

Expert Comment

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

LVL 6

Expert Comment

ID: 8075548
(note- there maybe a nicer way of doing this, I'm not sure).
0

LVL 9

Expert Comment

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

LVL 6

Expert Comment

ID: 8075691
If you always terminate the array of char with a chr(0) then StrPas will work nicely.
0

Author Comment

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

LVL 3

Expert Comment

ID: 8078630
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);

0

LVL 3

Expert Comment

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

0

LVL 9

Expert Comment

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

Author Comment

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

Author Comment

ID: 8085937
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;
0

LVL 3

Expert Comment

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

Author Comment

ID: 8100547
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'

0

Author Comment

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

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,
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
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
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.
0

LVL 3

Accepted Solution

Slavak earned 165 total points
ID: 8101310
I still cannot compile it (missing files).

If you want, send your code to slavak@programmer.net and I will try to fix it.
0

Author Comment

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

Author Comment

ID: 8117242
You answer do not solve the question, but help me to solve it, thanks.
0

## Featured Post

Question has a verified solution.

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

In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, thâ€¦