⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dimime.pas

📁 这是一个DELPHI7应用案例开发篇有配套程序种子光盘
💻 PAS
📖 第 1 页 / 共 2 页
字号:
{ The contents of this file are subject to the Mozilla Public License
  Version 1.1 (the "License"); you may not use this file except in
  compliance with the License. You may obtain a copy of the License at
  http://www.mozilla.org/MPL/

  Software distributed under the License is distributed on an "AS IS"
  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
  License for the specific language governing rights and limitations
  under the License.

  The Original Code is DIMime.pas.

  The Initial Developer of the Original Code is Ralf Junker <delphi@zeitungsjunge.de>.

  All Rights Reserved. }

{ ---------------------------------------------------------------------------- }

{ @abstract(Ligtening fast Mime (Base64) Encoding and Decoding routines.)
  @Author(Ralf Junker <delphi@zeitungsjunge.de>)
  The @Name unit contains some lightening fast Mime (Base64) Encoding and
  Decoding routines.
  <P>All functions and procedures are coded in carefully optimized Pascal.
  Even without using assembler, they are the fastest of their kind I know about. }

unit DIMime;

interface

{$I DI.inc}

{ @abstract(Mime-encodes an AnsiString.)
  @Name takes an AnsiString, encodes it, and returns the result as an AnsiString.
  To decode the result string, use @link(MimeDecodeString). }
function MimeEncodeString(const S: AnsiString): AnsiString;

{ @abstract(Mime-encodes an AnsiString.)
  @Name is just like @link(MimeEncodeString), but does <B>not</B> insert line breaks. }
function MimeEncodeStringNoCRLF(const S: AnsiString): AnsiString;

{ @abstract(Mime-decodes an AnsiString.)
  @Name takes a a string, decodes it, and returns the result as a string.
  Use @Name to decode a string previously encoded with link(MimeEncodeString). }
function MimeDecodeString(const S: AnsiString): AnsiString;

{ @abstract(Calculates Mime-encoding output size.)
  Calculates the output size of i MimeEncoded bytes, i.e. the memory required
  for all decoded data plus the line breaks. Use for @link(MimeEncode) only. }
function MimeEncodedSize(const InputSize: Cardinal): Cardinal;

{ @abstract(Calculates Mime-encoding output size.)
  Calculates the output size of i MimeEncodedNoCRLF bytes, i.e. the memory
  required for all decoded data. Use for @link(MimeEncodedNoCRLF) only. }
function MimeEncodedSizeNoCRLF(const InputSize: Cardinal): Cardinal;

{ @abstract(Calculates Mime-decoding output size.)
  Calculates the maximum output size of i MimeDecoded bytes.
  You may use it for @link(MimeDecode) to calculate the maximum amount of memory
  required for decoding in one single pass. }
function MimeDecodedSize(const InputSize: Cardinal): Cardinal;

{ @abstract(Decodes UserID and Password for HTTP Basic Authentication.)
  Decodes the UserID and Password for HTTP Basic Authentication. Pass the
  contents of the Authorization Header as BasicCredentials and DecodeHttpBasicAuthentication
  will return the unencoded UserID and Password. If either of the two can not be
  decoded or found, they will result in an empty string (''). This procedure is
  inspired by Shiv.
  <P>The following quote from "Request for Comments (RFC) 1945: Hypertext Transfer
  Protocol -- HTTP/1.0" has the details:
  <UL>
  <P>11.1  Basic Authentication Scheme
  <P>The "basic" authentication scheme is based on the model that the user
  agent must authenticate itself with a user-ID and a password for each
  realm. The realm value should be considered an opaque string which
  can only be compared for equality with other realms on that server.
  The server will authorize the request only if it can validate the
  user-ID and password for the protection space of the Request-URI.
  There are no optional authentication parameters.
  <P>Upon receipt of an unauthorized request for a URI within the
  protection space, the server should respond with a challenge like the
  following:
  <P>@code(WWW-Authenticate: Basic realm="WallyWorld")
  <P>where "WallyWorld" is the string assigned by the server to identify
  the protection space of the Request-URI.
  <P>To receive authorization, the client sends the user-ID and password,
  separated by a single colon (":") character, within a base64 [5]
  encoded string in the credentials.
  <P>@code(basic-credentials = "Basic" SP basic-cookie)
  <P>@code(basic-cookie) = @<base64 [5] encoding of userid-password, except not limited to 76 char/line@>
  <BR>@code(userid-password) = [ token ] ":" *TEXT
  <P>If the user agent wishes to send the user-ID "Aladdin" and password
  "open sesame", it would use the following header field:
  <P>@code(Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==)
  <P>The basic authentication scheme is a non-secure method of filtering
  unauthorized access to resources on an HTTP server. It is based on
  the assumption that the connection between the client and the server
  can be regarded as a trusted carrier. As this is not generally true
  on an open network, the basic authentication scheme should be used
  accordingly. In spite of this, clients should implement the scheme in
  order to communicate with servers that use it.
  </UL>}
procedure DecodeHttpBasicAuthentication(const BasicCredentials: AnsiString; out UserId, PassWord: AnsiString);

{ @abstract(Primary Mime encoding routine.)
  @Name is the primary Mime encoding routine. Line breaks will be inserted
  after each full line.
  <P><B>Caution</B>: OutputBuffer must have enough memory allocated to take all
  encoded output. @link(MimeEncodedSize)(InputBytesCount) calculates this amount
  in bytes. @Name will then fill the entire OutputBuffer, so there is no
  OutputBytesCount result for this procedure. Preallocating all memory at once
  (as required by @Name) avoids the time-cosuming process of reallocation.
  <P>If not all data fits into memory at once, you can <B>not</B> use @Name
  multiple times. Instead, use a combintion of @link(MimeEncodeFullLines) and
  @link(MimeEncodeNoCRLF). }
procedure MimeEncode(const InputBuffer; const InputByteCount: Cardinal; out OutputBuffer);

{ @abstract(Primary Mime encoding routine.)
  @Name is just like @link(MimeEncode), but does <B>not</B> insert line breaks.
  <P>Unlike @link(MimeEncode), you can use @NAme multiple times if not all data
  fits into memory at once. But you must be very careful about the size
  of the InputBuffer. See comments on @link(BUFFER_SIZE) for details
  and @link(MimeEncodeStreamNoCRLF) for an example. }
procedure MimeEncodeNoCRLF(const InputBuffer; const InputByteCount: Cardinal; out OutputBuffer);

{ @abstract(Internal Mime encoding helper routine.)
  @Name will decode full lines of @link(MIME_ENCODED_LINE_BREAK) length.
  A line break (CRLF) will be inserted after each line including the last one.
  Any remaining input which would not result in a full line will not be encoded.
  To encode the remaining partial line, use @link(MimeEncodeNoCRLF) with the
  appropriate parameters. @Name requires an OutputBuffer large enough for all
  encoded output. The required size of the OutputBuffer can be calculated with
  <P>@code((InputByteCount + 2) div 3 * 4 + InputByteCount div MIME_DECODED_LINE_BREAK * 2)
  <P>@Name will fill the entire OutputBuffer of that size. }
procedure MimeEncodeFullLines(const InputBuffer; const InputByteCount: Cardinal; out OutputBuffer);

{ @abstract(Primary Mime decoding routine.)
  The primary Mime decoding routines. @Name works with all MimeEncoded data,
  no matter if it was encoded with or without line breaks. Line breaks characters
  which are outside of the base64 alphabet and will be ignored.
  <P><B>Caution</B>: OutputBuffer must have enough memory allocated to take all output.
  @link(MimeDecodedSize)(InputBytesCount) calculates this amount in bytes. There is
  no guarantee that all output will be filled after decoding. All decoding
  functions therefore return the acutal number of bytes written to OutputBuffer.
  Preallocating all memory at once (as is required by MimeDecode)
  avoids the time-cosuming process of reallocation. After calling
  @Name, simply cut the allocated memory down to OutputBytesCount,
  i.e. calling @code(SetLength (OutString, OutputBytesCount)) for strings.
  <P>If not all data fits into memory at once, you may <B>not</B> use @Name multiple
  times. Instead, you must use a combination of @link(MimeDecodePartial) and
  @link(MimeDecodePartialEnd) functions. See @link(MimeDecodeStream) for an example. }
function MimeDecode(const InputBuffer; const InputBytesCount: Cardinal; out OutputBuffer): Cardinal;

{ @abstract(Internal Mime decoding helper routine.)
  The @Name function is mostly for internal use. It serves the purpose of
  decoding very large data in multiple parts of smaller chunks, as in
  @link(MimeDecodeStream).
  <P>Used in conjunction with @link(MimeDecodePartialEnd). }
function MimeDecodePartial(const InputBuffer; const InputBytesCount: Cardinal; out OutputBuffer; var ByteBuffer: Cardinal; var ByteBufferSpace: Cardinal): Cardinal;

{ @abstract(Internal Mime decoding helper routine.)
  The @Name function is mostly for internal use. It serves the purpose of
  decoding very large data in multiple parts of smaller chunks, as in
  @link(MimeDecodeStream).
  <P>Used in conjunction with @link(MimeDecodePartial). }
function MimeDecodePartialEnd(out OutputBuffer; const ByteBuffer: Cardinal; const ByteBufferSpace: Cardinal): Cardinal;

const
  { According to RFC 2045, @Name defaults to 76.
    If you ever need to change it, make sure it is a positive multiple of 4. }
  MIME_ENCODED_LINE_BREAK = 76;

  { Do not change this, even if you change @link(MIME_ENCODED_LINE_BREAK).
    @Name will always be a multiple of 3. }
  MIME_DECODED_LINE_BREAK = MIME_ENCODED_LINE_BREAK div 4 * 3;

implementation

const
  { The mime encoding table. Do not alter. }
  MIME_ENCODE_TABLE: array[0..63] of Byte = (
    065, 066, 067, 068, 069, 070, 071, 072, //  00 - 07
    073, 074, 075, 076, 077, 078, 079, 080, //  08 - 15
    081, 082, 083, 084, 085, 086, 087, 088, //  16 - 23
    089, 090, 097, 098, 099, 100, 101, 102, //  24 - 31
    103, 104, 105, 106, 107, 108, 109, 110, //  32 - 39
    111, 112, 113, 114, 115, 116, 117, 118, //  40 - 47
    119, 120, 121, 122, 048, 049, 050, 051, //  48 - 55
    052, 053, 054, 055, 056, 057, 043, 047); // 56 - 63

  MIME_PAD_CHAR = Byte('=');

  MIME_DECODE_TABLE: array[Byte] of Cardinal = (
    255, 255, 255, 255, 255, 255, 255, 255, //   0 -   7
    255, 255, 255, 255, 255, 255, 255, 255, //   8 -  15
    255, 255, 255, 255, 255, 255, 255, 255, //  16 -  23
    255, 255, 255, 255, 255, 255, 255, 255, //  24 -  31
    255, 255, 255, 255, 255, 255, 255, 255, //  32 -  39
    255, 255, 255, 062, 255, 255, 255, 063, //  40 -  47
    052, 053, 054, 055, 056, 057, 058, 059, //  48 -  55
    060, 061, 255, 255, 255, 255, 255, 255, //  56 -  63
    255, 000, 001, 002, 003, 004, 005, 006, //  64 -  71
    007, 008, 009, 010, 011, 012, 013, 014, //  72 -  79
    015, 016, 017, 018, 019, 020, 021, 022, //  80 -  87
    023, 024, 025, 255, 255, 255, 255, 255, //  88 -  95
    255, 026, 027, 028, 029, 030, 031, 032, //  96 - 103
    033, 034, 035, 036, 037, 038, 039, 040, // 104 - 111
    041, 042, 043, 044, 045, 046, 047, 048, // 112 - 119
    049, 050, 051, 255, 255, 255, 255, 255, // 120 - 127
    255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255);

type
  PByte4 = ^TByte4;
  TByte4 = packed record
    b1: Byte;
    b2: Byte;
    b3: Byte;
    b4: Byte;
  end;

  PByte3 = ^TByte3;
  TByte3 = packed record
    b1: Byte;
    b2: Byte;
    b3: Byte;
  end;

  PCardinal = ^Cardinal;

  { ---------------------------------------------------------------------------- }
  { String Encoding & Decoding
  { ---------------------------------------------------------------------------- }

function MimeEncodeString(const S: AnsiString): AnsiString;
var
  L: Cardinal;
begin
  if Pointer(S) <> nil then
    begin
      L := PCardinal(Cardinal(S) - 4)^;
      SetLength(Result, MimeEncodedSize(L));
      MimeEncode(Pointer(S)^, L, Pointer(Result)^);
    end
  else
    Result := '';
end;

{ ---------- }

function MimeEncodeStringNoCRLF(const S: AnsiString): AnsiString;
var
  L: Cardinal;
begin
  if Pointer(S) <> nil then
    begin
      L := PCardinal(Cardinal(S) - 4)^;
      SetLength(Result, MimeEncodedSizeNoCRLF(L));
      MimeEncodeNoCRLF(Pointer(S)^, L, Pointer(Result)^);
    end
  else
    Result := '';
end;

{ ---------- }

function MimeDecodeString(const S: AnsiString): AnsiString;
var
  ByteBuffer, ByteBufferSpace: Cardinal;
  L: Cardinal;
begin
  if Pointer(S) <> nil then
    begin
      L := PCardinal(Cardinal(S) - 4)^;
      SetLength(Result, MimeDecodedSize(L));
      ByteBuffer := 0;
      ByteBufferSpace := 4;
      L := MimeDecodePartial(Pointer(S)^, L, Pointer(Result)^, ByteBuffer, ByteBufferSpace);
      Inc(L, MimeDecodePartialEnd(Pointer(Cardinal(Result) + L)^, ByteBuffer, ByteBufferSpace));
      SetLength(Result, L);
    end
  else
    Result := '';
end;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -