Кодирование и декодирование BASE64 не работает

Я работаю над приложением для Android в Delphi XE5, и мне нужно кодировать и декодировать BASE64 некоторые строки.

Эта функция отлично работает для английских символов, но то, что я хочу закодировать €, $ или любую специальную кодировку символов iso8859-2, не работает.

Есть идеи, как это исправить?

Я нашел модуль BASE64 http://www.delphipraxis.net/991-base64-mime-en-decoding.html

Но поддерживает ли FireMonkey типы AnsiString и PAnsiChar и какой модуль нужно включить для использования этого типа?

Мой код

uses IdCoderMIME;
...

function Encode64(S: string): string;
var
  IdEncoderMIME: TIdEncoderMIME;
begin
  try
    IdEncoderMIME := TIdEncoderMIME.Create(nil);
    Result := IdEncoderMIME.EncodeString(S);
  finally
    IdEncoderMIME.Free;
  end;
end;

function Decode64(S: string): string;
var
  IdDecoderMIME: TIdDecoderMIME;
var
  IdDecoderMIME: TIdDecoderMIME;
begin
  try
    IdDecoderMIME := TIdDecoderMIME.Create(nil);
    Result := IdDecoderMIME.DecodeString(S);
  finally
    IdDecoderMIME.Free;
  end;
end;

person xJernej    schedule 25.02.2014    source источник
comment
BASE64 — это строковое представление набора байтов. Чтобы получить байты из строки, вам также нужно посмотреть кодировку (ASCII, ANSI, UTF8,...) строки и какую кодировку поддерживает/ожидает цель. TEncoding.GetBytes. Кстати, это не связано с FireMonkey   -  person Sir Rufo    schedule 26.02.2014
comment
Вы используете Indy в своем приложении?   -  person David Heffernan    schedule 28.02.2014


Ответы (2)


Официально Delphi НЕ поддерживает AnsiString и (P)AnsiChar на мобильных платформах. Неофициально код поддержки для них все еще присутствует в компиляторе и RTL, он просто скрыт, поэтому вы больше не можете получить к нему доступ. Доступен сторонний патч, разрешает доступ.

При кодировании/декодировании строки необходимо учитывать кодировку символов. Base64 кодирует байты, а не символы. Вы должны преобразовать строку в последовательность байтов, прежде чем Base64 кодирует байты, а затем Base64 декодирует последовательность байтов, прежде чем преобразовать ее обратно в строку.

Методы TIdEncoderMIME.EncodeString() и TIdDecoderMIME.DecodeString() имеют необязательный параметр TIdTextEncoding или IIdTextEncoding (в зависимости от вашей версии Indy) для преобразования строки‹->bytes. Если вы не укажете кодировку текста, Indy будет использовать текстовую кодировку по умолчанию, которая по умолчанию является 7-битной ASCII (настраивается с помощью переменной IdGlobal.GIdDefaultTextEncoding).

Например:

uses
  ..., IdGlobal, IdCoderMIME;

function Encode64(const S: string: const ByteEncoding: IIdTextEncoding = nil): string;
begin
  Result := TIdEncoderMIME.EncodeString(S, ByteEncoding);
end;

function Decode64(const S: string: const ByteEncoding: IIdTextEncoding = nil): string;
begin
  Result := TIdDecoderMIME.DecodeString(S, ByteEncoding);
end;

uses
  ..., IdGlobal;

var
  s, base64: string;
begin
  s := '€$';
  base64 := Encode64(s, IndyTextEncoding_UTF8);
  s := Decode64(base64, IndyTextEncoding_UTF8);
end;

uses
  ..., IdGlobal;

var
  s, base64: string;
  enc: IIdTextEncoding;
begin
  enc := IndyTextEncoding(28592); // ISO-8859-2
  s := '€$';
  base64 := Encode64(s, enc);
  s := Decode64(base64, enc);
end;

uses
  ..., IdGlobal, IdGlobalProtocols;

var
  s, base64: string;
  enc: IIdTextEncoding;
begin
  enc := CharsetToEncoding('ISO-8859-2');
  s := '€$';
  base64 := Encode64(s, enc);
  s := Decode64(base64, enc);
person Remy Lebeau    schedule 26.02.2014

Ключевым моментом является то, что base64 — это кодирование байтовых массивов в текст. Поэтому, если вы хотите закодировать текст, вы должны сначала преобразовать текст в массив байтов. И для этого вам нужно выбрать определенную кодировку текста.

Для примера предположим, что ваша текстовая кодировка — UTF-8. Процедура кодирования текста в base64 выполняется следующим образом:

  1. Закодируйте обычный текст в массив байтов, используя кодировку UTF-8.
  2. Закодируйте этот массив байтов в строку base64.

В обратном направлении это происходит так:

  1. Декодируйте строку base64 в массив байтов.
  2. Декодируйте массив байтов в строку, используя кодировку UTF-8.

Delphi поставляется с библиотеками, которые могут выполнять все эти шаги. Класс TEncoding обрабатывает часть UTF-8, а модуль Soap.EncdDecd — base64. Здесь нет необходимости использовать Indy только для выполнения кодирования base64.

К сожалению, функции EncodeString и DecodeString в Soap.EncdDecd не корректно обрабатывают Unicode. Я предпочитаю их избегать и делать все это с помощью функций EncodeStream и DecodeStream. Как это:

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;
person David Heffernan    schedule 26.02.2014