1

I am using Indy 10 with Delphi. Following is my code which uses EncodeString method of Indy to encode a string.

var
  EncodedString : String;
  StringToBeEncoded : String;
  EncoderMIME: TIdEncoderMIME;
....
....
EncodedString := EncoderMIME.EncodeString(StringToBeEncoded);

I am not getting the correct value in encoded sting.

  • Which encoding do you want to use? Regarding the question you asked, the answer is in the source code. Please read it and see if you can work out the answer. – David Heffernan Jul 30 '14 at 07:03
  • One wonders why you appear to be keen to use ANSI. Once again I find myself recommending that you learn about Unicode. Would you please consider doing so? – David Heffernan Jul 30 '14 at 07:13
  • So which encoding do you **want** to use? And why do you appear to want to use ANSI? And why haven't you looked in the Indy source? Do you know how to do that? – David Heffernan Jul 30 '14 at 07:18
  • 1
    I take the point of the other comments, but my +1 is for the q asking for an explanation rather than a solution ... – MartynA Jul 30 '14 at 07:21
  • OK. That's better. UTF-8 is probably a good choice. And I'm sure the Indy code works fine. So I wonder why you want to use ANSI. And again I wonder why you don't look in the Indy source. Since Indy is essentially undocumented (docs way out of date) the source is where you need to look for info. – David Heffernan Jul 30 '14 at 07:23
  • And I suppose the other issue I see is that we don't know which Indy version you used with D7. – David Heffernan Jul 30 '14 at 07:29

1 Answers1

2

What is the purpose of IndyTextEncoding_OSDefault?

Here's the source code for IndyTextEncoding_OSDefault.

function IndyTextEncoding_OSDefault: IIdTextEncoding;
begin
  if GIdOSDefaultEncoding = nil then begin
    LEncoding := TIdMBCSEncoding.Create;
    if InterlockedCompareExchangeIntf(IInterface(GIdOSDefaultEncoding), LEncoding, nil) <> nil then begin
      LEncoding := nil;
    end;
  end;
  Result := GIdOSDefaultEncoding;
end;

Note that I stripped out the .net conditional code for simplicity. Most of this code is to arrange singleton thread-safety. The actual value returned is synthesised by a call to TIdMBCSEncoding.Create. Let's look at that.

constructor TIdMBCSEncoding.Create;
begin
  Create(CP_ACP, 0, 0);
end;

Again I've remove conditional code that does not apply to your Windows setting. Now, CP_ACP is the Active Code Page, the current system Windows ANSI code page. So, on Windows at least, IndyTextEncoding_OSDefault is an encoding for the current system Windows ANSI code page.


Why did using IndyTextEncoding_OSDefault give the same behaviour as my Delphi 7 code?

That's because the Delphi 7 / Indy 9 code for TEncoderMIME.EncodeString does not perform any code page transformation and MIME encodes the input string as though it were a byte array. Since the Delphi 7 string is encoded in the active ANSI code page, this has the same effect as passing IndyTextEncoding_OSDefault to TEncoderMIME.EncodeString in your Unicode version of the code.


What is the difference between IndyTextEncoding_Default and IndyTextEncoding_OSDefault?

Here is the source code for IndyTextEncoding_OSDefault:

function IndyTextEncoding_Default: IIdTextEncoding;
var
  LType: IdTextEncodingType;
begin
  LType := GIdDefaultTextEncoding;
  if LType = encIndyDefault then begin
    LType := encASCII;
  end;
  Result := IndyTextEncoding(LType);
end;

This returns an encoding that is determined by the value of GIdDefaultTextEncoding. By default, GIdDefaultTextEncoding is encASCII. And so, by default, IndyTextEncoding_Default yields an ASCII encoding.


Beyond all this you should be asking yourself which encoding you want to be using. Relying on default values leaves you at the mercy of those defaults. What if those defaults don't do what you want to do. Especially as the defaults are not Unicode encodings and so support only a limited range of characters. And what's more are dependent on system settings.

If you wish to encode international text, you would normally choose to use the UTF-8 encoding.


One other point to make is that you are calling EncodeString as though it were an instance method, but it is actually a class method. You can remove EncoderMIME and call TEncoderMIME.EncodeString. Or keep EncoderMIME and call EncoderMIME.Encode.

Community
  • 1
  • 1
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490