Кодирането и декодирането на 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) за това преобразуване на низ‹->байтове. Ако не посочите текстово кодиране, Indy ще използва стандартното си текстово кодиране, което е 7bit 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