How to encode strings with EncdDec library

后端 未结 2 1293
礼貌的吻别
礼貌的吻别 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:07

    Quick fix:

    ANSI is enough for me since the text resulted after encoding must be as short as possible (easy to send via email). So, I put my ANSI string into a stream and encoded/decoded the stream. It worked!


    Jesus. Some documentation (at least a single comment line) would have been nice!

    0 讨论(0)
  • 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
    
    0 讨论(0)
提交回复
热议问题