[Solved] Delphi changing Chars in string – missunderstood behavior – XE3


There are several problems with your approach.

One problem is with your use of String.Replace(), which replaces ALL occurrences of one Char with another Char. Once you replace a given Char, you can potentially replace that same index with a different value later on in your loops, thus trashing your data while you are looping.

Another problem is your decoding logic. You are allowing each un-encoded Char to be encoded with one of 5 different Chars. If those encoded Char values are duplicated at all across your Enc[1..71].Enc array for the same value of Encoder, you will not be able to know which Enc[1..71].Char to use for decoding. It is not enough that your arrays are simply random, but they also need to be unique for the same value of Encoder.

Also, your loops are redundant and overly complicated. They can be greatly simplified.

Try something more like this instead:

function TEncrypter.EncodeChar(Sign: Char; Encoder: integer) : Char;
var
  t: integer;
begin
  for t := 1 to 71 do
  begin
    if Sign = Enc[t].Char then
    begin
      Result := Enc[t].Enc[Encoder];
      Exit;
    end;
  end;
  Result := Sign;
end;

function TEncrypter.DecodeChar(Sign: Char; Encoder: integer) : Char;
var
  t: integer;
begin
  for t := 1 to 71 do
  begin
    if Sign = Enc[t].Enc[Encoder] then
    begin
      Result := Enc[t].Char;
      Exit;
    end;
  end;
  Result := Sign;
end;

procedure TEncrypter.Encode;
var
  t, u, h: integer;
  s: String;
begin
  for h := 0 to EncodeBuffer.Count-1 do
  begin
    s := EncodeBuffer.Strings[h];
    t := Length(s);
    if t > 0 then
    begin
      for u := 0 to t-1 do
      begin
        s[u+1] := EncodeChar(s[u+1], (h mod 5) + 1);
      end;
      EncodeBuffer.Strings[h] := s;
    end;
  end;
end;

procedure TEncrypter.Decode;
var
  t, u, h: integer;
  s: String;
begin
  for h := 0 to EncodeBuffer.Count-1 do
  begin
    s := EncodeBuffer.Strings[h];
    t := Length(s);
    if t > 0 then
    begin
      for u := 0 to t-1 do
      begin
        s[u+1] := DecodeChar(s[u+1], (h mod 5) + 1);
      end;
      EncodeBuffer.Strings[h] := s;
    end;
  end;
end;

// FormCreate

var
  I, J, K, L: Integer;
  Temp: Array[1..71] of Char;
  NumInTemp: Integer;
begin
  ...

  // initialize Enc[].Char as needed...
  for I := 1 to 71 do
  begin
    Enc[I].Char := ...;
  end;

  // uniquely initialize each Enc[].Enc array for one value of Encoder...
  for I := 1 to 5 do
  begin
    for J := 1 to 71 do
      Temp[J] := ...; // must be unique for this iteration of I...
    NumInTemp := 71;

    // randomly assign Temp array to Enc[I].Enc array
    for J := 1 to 71 do
    begin
      K := 1 + Random(NumInTemp);
      Enc[J].Enc[I] := Temp[K];
      for L := K+1 to NumInTemp do
        Temp[L-1] := Temp[L];
      Dec(NumInTemp);
    end;
  end;
  ...
end;

If you then expand your arrays to allow all printable ASCII characters, not just 71 of them, then the code gets a little simpler:

var
  Enc : array [32..126] of Record
    Char: Char;
    Encr: string;
    Enc: array [1..5] of Char;
  end;

  EncodeBuffer: TStringList;

function TEncrypter.EncodeChar(Sign: Char; Encoder: integer) : Char;
var
  t: integer;
begin
  if (Sign >= #32) and (Sign <= #126) then
    Result := Enc[Ord(Sign)].Enc[Encoder]
  else
    Result := Sign;
end;

function TEncrypter.DecodeChar(Sign: Char; Encoder: integer) : Char;
var
  t: integer;
begin
  for t := Low(Enc) to High(Enc) do
  begin
    if Sign = Enc[t].Enc[Encoder] then
    begin
      Result := Enc[t].Char;
      Exit;
    end;
  end;
  Result := Sign;
end;

procedure TEncrypter.Encode;
var
  u, h: integer;
  s: String;
begin
  for h := 0 to EncodeBuffer.Count-1 do
  begin
    s := EncodeBuffer.Strings[h];
    for u := Low(s) to High(s) do
      s[u] := EncodeChar(s[u], (h mod 5) + 1);
    EncodeBuffer.Strings[h] := s;
  end;
end;

procedure TEncrypter.Decode;
var
  u, h: integer;
  s: String;
begin
  for h := 0 to EncodeBuffer.Count-1 do
  begin
    s := EncodeBuffer.Strings[h];
    for u := Low(s) to High(s) do
      s[u] := DecodeChar(s[u], (h mod 5) + 1);
    EncodeBuffer.Strings[h] := s;
  end;
end;

// FormCreate

var
  I, J, K, L: Integer;
  Temp: Array[32..126] of Char;
  NumInTemp: Integer;
begin
  ...

  for I := Low(Enc) to High(Enc) do
    Enc[I].Char := Char(I);

  for I := 1 to 5 do
  begin
    for J := Low(Temp) to High(Temp) do
      Temp[J] := Char(J);
    NumInTemp := Length(Temp);

    for J := Low(Enc) to High(Enc) do
    begin
      K := Low(Temp) + Random(NumInTemp);
      Enc[J].Enc[I] := Temp[K];
      for L := K+1 to (Low(Temp)+NumInTemp) do
        Temp[L-1] := Temp[L];
      Dec(NumInTemp);
    end;
  end;
end;

And if you set up a separate decoder table instead of using Enc[].Enc, you can simplify TEncrypter.DecodeChar() to a similar lookup that TEncrypter.EncodeChar() uses, without having to use a loop at all. I will leave that as an exercise for you.

16

solved Delphi changing Chars in string – missunderstood behavior – XE3