Простой MIME Base64 декодер - PullRequest
3 голосов
/ 11 июля 2011

Я ищу простой способ, который не предполагает использования чего-то вроде Indy для простого декодирования Base64, содержащего то, что сказано в сообщении от Thunderbird.

Пример:

WW91ciBtZXNzYWdlDQoNCiAgVG86ICAgICAgeHh4QHh4eC5jb20NCiAgU3ViamVjdDogSXh4eA0KICBTZW50OiAgICBUaHUsIDIyIE9jdCAyMDA5IDAxOjE0OjM0IC0wNDAwDQoNCmRpZCBub3QgcmVhY2ggdGhlIGZvbGxvd2luZyByZWNpcGllbnQocyk6DQoNCnh4eEBneHh4IG9uIFR1ZSwgMjcgT2N0IDIwMDkgMDE6NDA6NDQgLTA0MDANCiAgICBUaGUgZS1tYWlsIHN5c3RlbSB3YXMgdW5hYmxlIHRvIGRlbGl2ZXIgdGhlIG1lc3NhZ2UsIGJ1dCBkaWQgbm90DQpyZXBvcnQgYSBzcGVjaWZpYyByZWFzb24uICBDaGVjayB0aGUgYWRkcmVzcyBhbmQgdHJ5IGFnYWluLiAgSWYgaXQgc3RpbGwNCmZhaWxzLCBjb250YWN0IHlvdXIgc3lzdGVtIGFkbWluaXN0cmF0b3IuDQogICAgPCBDaW54eHguY29tICM1LjAuMCBzbXRwOyA1LjQuNyAtIERlbGl2ZXJ5IGV4cGlyZWQNCihtZXNzYWdlIHRvbyBvbGQpICd0aW1lb3V0JyAoZGVsaXZlcnkgYXR0ZW1wdHM6IDApPg==

Становится: Ваше сообщение

  To:      xxx@xxx.com
  Subject: Ixxx
  Sent:    Thu, 22 Oct 2009 01:14:34 -0400

did not reach the following recipient(s):

xxx@gxxx on Tue, 27 Oct 2009 01:40:44 -0400
    The e-mail system was unable to deliver the message, but did not
report a specific reason.  Check the address and try again.  If it still
fails, contact your system administrator.
    < Cinxxx.com #5.0.0 smtp; 5.4.7 - Delivery expired
(message too old) 'timeout' (delivery attempts: 0)>

Edit: кажется, что максимальная длина строки MIME Base64 может быть 76. Мне нужно декодировать каждую 76-битную длинную строку, а не все сообщение сразу. Спасибо.

Ответы [ 4 ]

8 голосов
/ 12 июля 2011

Начиная с Delphi 6, Delphi включает модуль EncdDecd, который включает в себя функцию DecodeString , которая декодирует строку Input, содержащую текст base64, в строку Result с фактическими декодированными данными ( который может быть двоичным):

function DecodeString(const Input: string): string;

Начиная с Delphi 2009, он также включает функцию DecodeBase64 , которая декодирует Input AnsiString в двоичный файл Result ТБ:

function  DecodeBase64(const Input: AnsiString): TBytes;

В дополнение к более раннему ответу Delphi / PHP base64 , который я дал, я сейчас написал небольшой модульный тест, который показывает, как работают DecodeString и EncodeString:

unit Base64TestCaseUnit;

interface

uses
  Classes, SysUtils, TestFrameWork, Generics.Collections;

{
 base64 test vectors: http://tools.ietf.org/html/rfc4648
   BASE64("") = ""
   BASE64("f") = "Zg=="
   BASE64("fo") = "Zm8="
   BASE64("foo") = "Zm9v"
   BASE64("foob") = "Zm9vYg=="
   BASE64("fooba") = "Zm9vYmE="
   BASE64("foobar") = "Zm9vYmFy"
}
const
  Key_ = '';
  Value_ = '';
  Key_f = 'f';
  Value_f = 'Zg==';
  Key_fo = 'fo';
  Value_fo = 'Zm8=';
  Key_foo = 'foo';
  Value_foo = 'Zm9v';
  Key_foob = 'foob';
  Value_foob = 'Zm9vYg==';
  Key_fooba = 'fooba';
  Value_fooba = 'Zm9vYmE=';
  Key_foobar = 'foobar';
  Value_foobar = 'Zm9vYmFy';
// binary test vector
  Key_binary = #1#2#3#4;
  Value_binary = 'AQIDBA==';

type
  TStringStringDictionary = TDictionary<string, string>;
  TBase64TestCase = class(TTestCase)
  strict private
    FBase64VectorsDictionary: TStringStringDictionary;
  strict protected
    procedure DecodeTestOneKey(const ExpectedKey: string); virtual;
    procedure EncodeTestOneKey(const ActualKey: string); virtual;
    property Base64VectorsDictionary: TStringStringDictionary read FBase64VectorsDictionary;
  protected
    procedure SetUp; override;
    procedure TearDown; override;
  published
    {$IFDEF CLR}[Test]{$ENDIF}
    procedure Base64_DecodeString_Test_;
    {$IFDEF CLR}[Test]{$ENDIF}
    procedure Base64_DecodeString_Test_binary;
    {$IFDEF CLR}[Test]{$ENDIF}
    procedure Base64_DecodeString_Test_f;
    {$IFDEF CLR}[Test]{$ENDIF}
    procedure Base64_DecodeString_Test_fo;
    {$IFDEF CLR}[Test]{$ENDIF}
    procedure Base64_DecodeString_Test_foo;
    {$IFDEF CLR}[Test]{$ENDIF}
    procedure Base64_DecodeString_Test_foob;
    {$IFDEF CLR}[Test]{$ENDIF}
    procedure Base64_DecodeString_Test_fooba;
    {$IFDEF CLR}[Test]{$ENDIF}
    procedure Base64_DecodeString_Test_foobar;
    {$IFDEF CLR}[Test]{$ENDIF}
    procedure Base64_EncodeString_Test_;
    {$IFDEF CLR}[Test]{$ENDIF}
    procedure Base64_EncodeString_Test_binary;
    {$IFDEF CLR}[Test]{$ENDIF}
    procedure Base64_EncodeString_Test_f;
    {$IFDEF CLR}[Test]{$ENDIF}
    procedure Base64_EncodeString_Test_fo;
    {$IFDEF CLR}[Test]{$ENDIF}
    procedure Base64_EncodeString_Test_foo;
    {$IFDEF CLR}[Test]{$ENDIF}
    procedure Base64_EncodeString_Test_foob;
    {$IFDEF CLR}[Test]{$ENDIF}
    procedure Base64_EncodeString_Test_fooba;
    {$IFDEF CLR}[Test]{$ENDIF}
    procedure Base64_EncodeString_Test_foobar;
  end;

implementation

uses
  EncdDecd;

procedure TBase64TestCase.Base64_DecodeString_Test_;
begin
  DecodeTestOneKey(Key_);
end;

procedure TBase64TestCase.Base64_DecodeString_Test_binary;
begin
  DecodeTestOneKey(Key_binary);
end;

procedure TBase64TestCase.Base64_DecodeString_Test_f;
begin
  DecodeTestOneKey(Key_f);
end;

procedure TBase64TestCase.Base64_DecodeString_Test_fo;
begin
  DecodeTestOneKey(Key_fo);
end;

procedure TBase64TestCase.Base64_DecodeString_Test_foo;
begin
  DecodeTestOneKey(Key_foo);
end;

procedure TBase64TestCase.Base64_DecodeString_Test_foob;
begin
  DecodeTestOneKey(Key_foob);
end;

procedure TBase64TestCase.Base64_DecodeString_Test_fooba;
begin
  DecodeTestOneKey(Key_fooba);
end;

procedure TBase64TestCase.Base64_DecodeString_Test_foobar;
begin
  DecodeTestOneKey(Key_foobar);
end;

procedure TBase64TestCase.SetUp;
begin
  FBase64VectorsDictionary := TStringStringDictionary.Create();
  FBase64VectorsDictionary.Add(Key_, Value_);
  FBase64VectorsDictionary.Add(Key_f, Value_f);
  FBase64VectorsDictionary.Add(Key_fo, Value_fo);
  FBase64VectorsDictionary.Add(Key_foo, Value_foo);
  FBase64VectorsDictionary.Add(Key_foob, Value_foob);
  FBase64VectorsDictionary.Add(Key_fooba, Value_fooba);
  FBase64VectorsDictionary.Add(Key_foobar, Value_foobar);
  FBase64VectorsDictionary.Add(Key_binary, Value_binary);
end;

procedure TBase64TestCase.TearDown;
begin
  FBase64VectorsDictionary.Free();
  FBase64VectorsDictionary := nil;
end;

procedure TBase64TestCase.Base64_EncodeString_Test_;
begin
  EncodeTestOneKey(Key_);
end;

procedure TBase64TestCase.Base64_EncodeString_Test_binary;
begin
  EncodeTestOneKey(Key_binary);
end;

procedure TBase64TestCase.Base64_EncodeString_Test_f;
begin
  EncodeTestOneKey(Key_f);
end;

procedure TBase64TestCase.Base64_EncodeString_Test_fo;
begin
  EncodeTestOneKey(Key_fo);
end;

procedure TBase64TestCase.Base64_EncodeString_Test_foo;
begin
  EncodeTestOneKey(Key_foo);
end;

procedure TBase64TestCase.Base64_EncodeString_Test_foob;
begin
  EncodeTestOneKey(Key_foob);
end;

procedure TBase64TestCase.Base64_EncodeString_Test_fooba;
begin
  EncodeTestOneKey(Key_fooba);
end;

procedure TBase64TestCase.Base64_EncodeString_Test_foobar;
begin
  EncodeTestOneKey(Key_foobar);
end;

procedure TBase64TestCase.DecodeTestOneKey(const ExpectedKey: string);
var
  ActualKey: string;
  ExpectedValue: string;
begin
  ExpectedValue := FBase64VectorsDictionary[ExpectedKey];
  ActualKey := DecodeString(ExpectedValue);
  Self.CheckEquals(ExpectedKey, ActualKey, Format('base64 decode of "%s" should be "%s"', [ExpectedValue, ExpectedKey]));
end;

procedure TBase64TestCase.EncodeTestOneKey(const ActualKey: string);
var
  ActualValue: string;
  ExpectedValue: string;
begin
  ExpectedValue := FBase64VectorsDictionary[ActualKey];
  ActualValue := EncodeString(ActualKey);
  Self.CheckEquals(ExpectedValue, ActualValue, Format('base64 of "%s" should be "%s"', [ActualKey, ExpectedValue]));
end;

initialization
  RegisterTest('', TBase64TestCase.Suite);
end.
5 голосов
/ 11 июля 2011

Расшифровка не так уж и сложна, но вот блог с примером кода для Delphi

http://www.delphifaq.net/how-to-base-64-mime-encode-and-decode-a-string/

Основная идея состоит в том, что существует 64 символа, каждыйпредставляют битовую комбинацию для 6 бит.Вы возвращаете символ к его 6 битам с помощью поиска в таблице, а затем берете свой список битов и разбиваете их на 8-битные куски, чтобы получить байты.

1 голос
/ 13 июля 2011
uses
  Math;

var
  Base64: array[0..63] of AnsiChar = (
    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
    'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
    'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
    'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
    'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
    'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
    'w', 'x', 'y', 'z', '0', '1', '2', '3',
    '4', '5', '6', '7', '8', '9', '+', '/');

function IndexOfBase64(const C: AnsiChar): Integer;
begin
  for Result := Low(Base64) to High(Base64) do
    if Base64[Result] = C then
      EXIT;
  Result := -1;
end;

function DecodeBase64(Value: AnsiString): AnsiString;
var
  iC, iB: Integer;
  B: array of Integer;
  C: array[0..3] of Integer;
begin
  SetLength(B, Floor(Length(Value) / 4) * 3);

  iC := 1;
  iB := 0;
  while iC <= (Length(Value) - 3) do
  begin
    C[0] := IndexOfBase64(Value[iC]);
    C[1] := IndexOfBase64(Value[iC + 1]);
    C[2] := IndexOfBase64(Value[iC + 2]);
    C[3] := IndexOfBase64(Value[iC + 3]);

    B[iB]     := (C[0] shl 2) or (C[1] shr 4);
    B[iB + 1] := ((C[1] and 15) shl 4) or (C[2] shr 2);
    B[iB + 2] := ((C[2] and 3) shl 6) or C[3];

    Inc(iC, 4);
    Inc(iB, 3);
  end;

  SetLength(B, Length(B) - (Length(B) mod 16));

  for iB := 0 to High(B) do
    Result := Result + Chr(B[iB]);
end;
0 голосов
/ 11 июля 2011

Если вам нужно просто готовое решение, попробуйте DIMime

...