开发者

Simple MIME Base64 Decoder

开发者 https://www.devze.com 2023-03-19 06:09 出处:网络
I\'m looking for an easy way that doesn\'t involve using something like Indy to just decode Base64 that contains what the message from Thunderbird said.

I'm looking for an easy way that doesn't involve using something like Indy to just decode Base64 that contains what the message from Thunderbird said.

Example:

WW91ciBtZXNzYWdlDQoNCiAgVG86ICAgICAgeHh4QHh4eC5jb20NCiAgU3ViamVjdDogSXh4eA0KICBTZW50OiAgICBUaHUsIDIyIE9jdCAyMDA5IDAxOjE0OjM0IC0wNDAwDQoNCmRpZCBub3QgcmVhY2ggdGhlIGZvbGxvd2luZyByZWNpcGllbnQocyk6DQoNCnh4eEBneHh4IG9uIFR1ZSwgMjcgT2N0IDIwMDkgMDE6NDA6NDQgLTA0MDANCiAgICBUaGUgZS1tYWlsIHN5c3RlbSB3YXMgdW5hYmxlIHRvIGRlbGl2ZXIgdGhlIG1lc3NhZ2UsIGJ1dCBkaWQgbm90DQpyZXBvcnQgYSBzcGVjaWZpYyByZWFzb24uICBDaGVjayB0aGUgYWRkcmVzcyBhbmQgdHJ5IGFnYWluLiAgSWYgaXQgc3RpbGwNCmZhaWxzLCBjb250YWN0IHlvdXIgc3lzdGVtIGFkbWluaXN0cmF0b3IuDQogICAgPCBDaW54eHguY29tICM1LjAuMCBzbXRwOyA1LjQuNyAtIERlbGl2ZXJ5IGV4cGlyZWQNCihtZXNzYWdlIHRvbyBvbGQpICd0aW1lb3V0JyAoZGVsaXZlcnkgYXR0ZW1wdHM6IDApPg==

Becomes: Your message

  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: Seems that the max length a MIME Base64 line can be is 76. I 开发者_StackOverflow社区have to decode each 76 bit long line, not the entire message at once. Thanks.


Since Delphi 6, Delphi has included the EncdDecd unit, which includes the DecodeString function which decodes the Input string containing base64 text into a Result string with actual decoded data (which might be binary):

function DecodeString(const Input: string): string;

Since Delphi 2009, it also includes the DecodeBase64 function which decodes the Input AnsiString into a binary Result of TBytes:

function  DecodeBase64(const Input: AnsiString): TBytes;

In addition to an earlier Delphi/PHP base64 answer I gave, I now wrote a small unit test that shows how DecodeString and EncodeString work:

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.


The decoding isn't that hard to code up, but here's a blog with some sample code for Delphi

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

The basic idea is that there are 64 characters, each represent a bit pattern for 6 bits. You turn the character back to its 6 bits with a table look-up, and then you take your list of bits, and break them back into 8-bit chunks to make bytes.


If you just want a ready-rolled solution try DIMime


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

精彩评论

暂无评论...
验证码 换一张
取 消