How to encode strings with EncdDec library

后端 未结 2 1294
礼貌的吻别
礼貌的吻别 2021-01-16 07:26

I have this basic code that should encode a string and then get it back. However, the decoded text is garbage.

procedure TForm5.Button2Click(Sender: TObject)         


        
2条回答
  •  醉梦人生
    2021-01-16 08:10

    The problem is here, in the Soap.EncdDecd unit:

    function EncodeString(const Input: string): string;
    var
      InStr, OutStr: TStringStream;
    begin
      InStr := TStringStream.Create(Input);
      try
        OutStr := TStringStream.Create('');
        try
          EncodeStream(InStr, OutStr);
          Result := OutStr.DataString;
        finally
          OutStr.Free;
        end;
      finally
        InStr.Free;
      end;
    end;
    

    This code has not been updated for Unicode. The use of TStringStream for InStr without specifying an encoding is the problem. With no encoding specified, ANSI is used to decode to a byte array. And so only characters in the local ANSI code page are decoded correctly.

    The same mistake is made in the other direction in DecodeString.

    You can fix this readily enough by creating variants that specify a full Unicode encoding. For example:

    function EncodeString(const Input: string): string;
    var
      InStr, OutStr: TStringStream;
    begin
      InStr := TStringStream.Create(Input, TEncoding.UTF8);
      try
        OutStr := TStringStream.Create('');
        try
          EncodeStream(InStr, OutStr);
          Result := OutStr.DataString;
        finally
          OutStr.Free;
        end;
      finally
        InStr.Free;
      end;
    end;
    
    function DecodeString(const Input: string): string;
    var
      InStr, OutStr: TStringStream;
    begin
      InStr := TStringStream.Create(Input);
      try
        OutStr := TStringStream.Create('', TEncoding.UTF8);
        try
          DecodeStream(InStr, OutStr);
          Result := OutStr.DataString;
        finally
          OutStr.Free;
        end;
      finally
        InStr.Free;
      end;
    end;
    

    It doesn't matter which encoding you specify so long as it is a full Unicode encoding, and you use the same encoding in both directions!

    Clearly Embarcadero should be encouraged to make this change to their code.

    This program demonstrates that the fix works:

    {$APPTYPE CONSOLE}
    
    uses
      System.SysUtils, System.Classes, Soap.EncdDecd;
    
    function EncodeString(const Input: string): string;
    var
      InStr, OutStr: TStringStream;
    begin
      InStr := TStringStream.Create(Input, TEncoding.UTF8);
      try
        OutStr := TStringStream.Create('');
        try
          EncodeStream(InStr, OutStr);
          Result := OutStr.DataString;
        finally
          OutStr.Free;
        end;
      finally
        InStr.Free;
      end;
    end;
    
    function DecodeString(const Input: string): string;
    var
      InStr, OutStr: TStringStream;
    begin
      InStr := TStringStream.Create(Input);
      try
        OutStr := TStringStream.Create('', TEncoding.UTF8);
        try
          DecodeStream(InStr, OutStr);
          Result := OutStr.DataString;
        finally
          OutStr.Free;
        end;
      finally
        InStr.Free;
      end;
    end;
    
    const
      N = 256;
    
    var
      i: Integer;
      s1, s2: string;
    
    begin
      SetLength(s1, N);
      for i := 1 to N do
        s1[i] := Chr(i-1);
    
      s2 := Soap.EncdDecd.EncodeString(s1);
      s2 := Soap.EncdDecd.DecodeString(s2);
      Writeln(s1=s2);
    
      s2 := EncodeString(s1);
      s2 := DecodeString(s2);
      Writeln(s1=s2);
    end.
    

    Output:

    FALSE
    TRUE
    

提交回复
热议问题