This week I had to migrate an application from Delphi XE3 to Delphi Berlin and this application uses a Base64 encoding.
Normally Base64 encoding is not difficult stuff and Delphi XE3 simply offers the function EncodeString in the unit Soap.EncdDecd.
Since Delphi Berlin has the same function I thought that I didn’t have to change a single line of code. But the first thing I realized is that the function is nearly deprecated. This means that it already has a deprecated comment: // deprecated ‘Use TNetEncoding.Base64.Encode’.
Such a comment means that the function will become deprecated with one of the next Delphi releases.
A short look at the implementation shows the reason:
function EncodeString(const Input: string): string;
begin
Result := TNetEncoding.Base64.Encode(Input);
end;
I should call TNetEncoding.Base64.Encode directly instead of using the old function EncodeString.
But then I realized that the two Delphi versions show different results.
Let’s have a look at a small example with some German umlauts:
procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage(EncodeString('ÄäÖöÜüß'));
end;
Delphi XE3 shows ‘xOTW9tz83w==’ whereas Delphi Berlin shows ‘w4TDpMOWw7bDnMO8w58=’.
So bad luck, I had to have a deeper look at the code. Let’s start with Delphi XE3:
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;
...
constructor TStringStream.Create(const AString: string);
begin
Create(AString, TEncoding.Default, False);
end;
This means that the string is first converted into bytes with the help of the default encoding which is under Windows an ANSI encoding. After that the bytes are encoded.
Let’s have a look at the Delphi Berlin implementation:
function TNetEncoding.Encode(const Input: string): string;
begin
Result := DoEncode(Input);
end;
...
function TBase64Encoding.DoEncode(const Input: string): string;
begin
Result := DoEncodeBytesToString(TEncoding.UTF8.GetBytes(Input));
end;
Delphi Berlin always converts the string into UTF-8 bytes and then encodes the bytes. This means that the implementation of EncodeString in Delphi Berlin differs to the implementation in XE3.
To fix this issue let’s try the following implementation in Delphi Berlin:
procedure TForm1.Button1Click(Sender: TObject);
var
lBytes: TBytes;
begin
lBytes := TEncoding.Default.GetBytes('ÄäÖöÜüß');
lBytes := TNetEncoding.Base64.Encode(lBytes);
ShowMessage(TEncoding.Default.GetString(lBytes));
end;
I first convert the string into bytes with the help of the default encoding. Then I encode the bytes with the new Base64 class and at the end I have to convert the bytes back to a string.
I will contact Embarcadero/Idera and ask them if I should write a quality portal case.