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;
精彩评论