 |
| |
|
|
 |
Autor |
Nachricht |
 |
| |
| sakura |
#1| Verfasst am: 05.10.2002, 13:13 Titel: Base64 (MIME) En-/Decoding |
|
 |
 |
|
Super-Moderator Alter: 33 Status: offline Beiträge: 11.294 angemeldet: 10.06.2002 Wohnort: München RAD-Studio 2007 Architect

|
Sprache: Delphi (Win32) Jetzt wieder mal zwei optimierte Routinen, welche normalerweise durch die TIdEncoderMIME, TIdDecoderMIME (Indy Bibliothek) Komponenten abgedeckt werden.
Der Decodierer steht jetzt auch zur Verfügung.
Erster Grund contra der Indy Lösung: es ist eine Komponente (VCL).
Zweiter Grund contra der Indy Lösung: die ist seht langsam.
Code: | zusammenfalten | markieren | 1 · · · 5 · · · · 10
| Geschwindigkeiten in Ticks
==========================
Variante Encoding Decoding
Assembler ~110 ~290
INDY 9.x ~315 ~1490
Ticks - von GetTickCount
Rechner: 450 MHz Pentium; 128 MB RAM; innerhalb des D7 Debugger |
|
Der Base64/MIME Codec wird i.A. zum Codieren von z.B. EMail Attachments benutzt.
Delphi-Quellcode: | zusammenfalten | markieren | 1 · · · 5 · · · · 10 · · · · 15 · · · · 20 · · · · 25 · · · · 30 · · · · 35 · · · · 40 · · · · 45 · · · · 50 · · · · 55 · · · · 60 · · · · 65 · · · · 70 · · · · 75 · · · · 80 · · · · 85 · · · · 90 · · · · 95 · · · · 100 · · · · 105 · · · · 110 · · · · 115 · · · · 120 · · · · 125 · · · · 130 · · · · 135 · · · · 140 · · · · 145 · · · · 150 · · · · 155 · · · · 160 · · · · 165 · · · · 170 · · · · 175 · · · · 180 · · · · 185 · · · · 190 · · · · 195 · · · · 200 · · · · 205 · · · · 210 · · · · 215 · · · · 220 · · · · 225 · · · · 230 · · · · 235 · · · · 240 · · · · 245 · · · · 250 · · · · 255 · · · · 260 · · · · 265 · · · · 270 · · · · 275 · · · · 280 · · · · 285 · · · · 290 · · · · 295 · · · · 300 · · · · 305 · · · · 310 · · · · 315 · · · · 320 · · · · 325 · · · · 330 · · · · 335 · · · · 340 · · · · 345 · · · · 350 · · · · 355 · · · · 360 · · · · 365 · · · · 370 · · · · 375 · · · · 380 · · · · 385 · · · · 390 · · · · 395 · · · · 400 · · · · 405 · · · · 410 · · · · 415 · · · · 420 · · · · 425 · · · · 430 · · · · 435 · · · · 440 · · · · 445 · · · · 450 · · · · 455 · · · · 460 · · · · 465 · · · · 470 · · · · 475 · · · · 480 · · · · 485 · · · · 490 · · · · 495 · · · · 500 · · · · 505 · · · · 510 · · · · 515 · · · · 520 · · · · 525 · · · · 530 · · · · 535 · · · · 540 · · · · 545 · · · · 550 · · · · 555 · · · · 560 · · · · 565 · · · · 570 · 572
| {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Unit Name : uBase64Codec
* Author : Daniel Wischnewski
* Copyright : Copyright © 2001-2003 by gate(n)etwork GmbH. All Rights Reserved.
* Creator : Daniel Wischnewski
* Contact : Daniel Wischnewski (e-mail: delphi3000(at)wischnewski.tv);
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
// * * * License * * *
//
// The contents of this file are used with permission, 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/MPL-1.1.html
//
// 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.
//
// * * * My Wish * * *
//
// If you come to use this unit for your work, I would like to know about it.
// Drop me an e-mail and let me know how it worked out for you. If you wish, you
// can send me a copy of your work. No obligations!
// My e-mail address: delphi3000(at)wischnewski.tv
//
// * * * History * * *
//
// Version 1.0 (Oct-10 2002)
// first published on Delphi-PRAXiS (www.delphipraxis.net)
//
// Version 1.1 (May-13 2003)
// introduced a compiler switch (SpeedDecode) to switch between a faster
// decoding variant (prior version) and a litte less fast, but secure variant
// to work around bad formatted data (decoding only!)
//
// Version 1.2 (Juni-09 2004)
// included compiler switch {$0+}. In Delphi 6 and 7 projects using this code
// with compiler optimizations turned off will raise an access violation
// {$O+} will ensure that this unit runs with compiler optimizations.
// This option does *not* influence other parts of the project including this
// unit.
// Thanks to Ralf Manschewski for pointing out this problem.
//
unit Base64;
{$O+}
interface
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// !! THE COMPILER SWITCH MAY BE USED TO ADJUST THE BEHAVIOR !!
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// enable "SpeedDecode"
// the switch to gain speed while decoding the message, however, the codec
// will raise different exceptions/access violations or invalid output if
// the incoming data is invalid or missized.
// disable "SpeedDecode"
// the switch to enable a data check, that will scan the data to decode to
// be valid. This method is to be used if you cannot guarantee to validity
// of the data to be decoded.
{.DEFINE SpeedDecode}
{$IFNDEF SpeedDecode}
{$DEFINE ValidityCheck}
{$ENDIF}
uses SysUtils;
// codiert einen String in die zugehörige Base64-Darstellung
function Base64Encode(const InText: AnsiString): AnsiString; overload;
// decodiert die Base64-Darstellung eines Strings in den zugehörigen String
function Base64Decode(const InText: AnsiString): AnsiString; overload;
// bestimmt die Größe der Base64-Darstellung
function CalcEncodedSize(InSize: Cardinal): Cardinal;
// bestimmt die Größe der binären Darstellung
function CalcDecodedSize(const InBuffer; InSize: Cardinal): Cardinal;
// codiert einen Buffer in die zugehörige Base64-Darstellung
procedure Base64Encode(const InBuffer; InSize: Cardinal; var OutBuffer); overload; register;
// decodiert die Base64-Darstellung in einen Buffer
{$IFDEF SpeedDecode}
procedure Base64Decode(const InBuffer; InSize: Cardinal; var OutBuffer); overload; register;
{$ENDIF}
{$IFDEF ValidityCheck}
function Base64Decode(const InBuffer; InSize: Cardinal; var OutBuffer): Boolean; overload; register;
{$ENDIF}
// codiert einen String in die zugehörige Base64-Darstellung
procedure Base64Encode(const InText: PAnsiChar; var OutText: PAnsiChar); overload;
// decodiert die Base64-Darstellung eines Strings in den zugehörigen String
procedure Base64Decode(const InText: PAnsiChar; var OutText: PAnsiChar); overload;
// codiert einen String in die zugehörige Base64-Darstellung
procedure Base64Encode(const InText: AnsiString; var OutText: AnsiString); overload;
// decodiert die Base64-Darstellung eines Strings in den zugehörigen String
procedure Base64Decode(const InText: AnsiString; var OutText: AnsiString); overload;
implementation
const
cBase64Codec: array[0..63] of AnsiChar =
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
Base64Filler = '=';
function Base64Encode(const InText: string): string; overload;
begin
Base64Encode(InText, Result);
end;
function Base64Decode(const InText: string): string; overload;
begin
Base64Decode(InText, Result);
end;
function CalcEncodedSize(InSize: Cardinal): Cardinal;
begin
// no buffers passed along, calculate outbuffer size needed
Result := (InSize div 3) shl 2;
if ((InSize mod 3) > 0)
then Inc(Result, 4);
end;
function CalcDecodedSize(const InBuffer; InSize: Cardinal): Cardinal;
type
BA = array of Byte;
begin
Result := 0;
if InSize = 0 then
Exit;
if InSize mod 4 <> 0 then
Exit;
Result := InSize div 4 * 3;
if (BA(InBuffer)[InSize - 2] = Ord(Base64Filler))
then Dec(Result, 2)
else if BA(InBuffer)[InSize - 1] = Ord(Base64Filler)
then Dec(Result);
end;
procedure Base64Encode(const InBuffer; InSize: Cardinal; var OutBuffer
); register;
var
ByThrees, LeftOver: Cardinal;
// reset in- and outbytes positions
asm
// load addresses for source and destination
// PBYTE(InBuffer);
mov ESI, [EAX]
// PBYTE(OutBuffer);
mov EDI, [ECX]
// ByThrees := InSize div 3;
// LeftOver := InSize mod 3;
// load InSize (stored in EBX)
mov EAX, EBX
// load 3
mov ECX, $03
// clear upper 32 bits
xor EDX, EDX
// divide by ECX
div ECX
// save result
mov ByThrees, EAX
// save remainder
mov LeftOver, EDX
// load addresses
lea ECX, cBase64Codec[0]
// while I < ByThrees do
// begin
xor EAX, EAX
xor EBX, EBX
xor EDX, EDX
cmp ByThrees, 0
jz @@LeftOver
@@LoopStart:
// load the first two bytes of the source triplet
LODSW
// write Bits 0..5 to destination
mov BL, AL
shr BL, 2
mov DL, BYTE PTR [ECX + EBX]
// save the Bits 12..15 for later use [1]
mov BH, AH
and BH, $0F
// save Bits 6..11
rol AX, 4
and AX, $3F
mov DH, BYTE PTR [ECX + EAX]
mov AX, DX
// store the first two bytes of the destination quadruple
STOSW
// laod last byte (Bits 16..23) of the source triplet
LODSB
// extend bits 12..15 [1] with Bits 16..17 and save them
mov BL, AL
shr BX, 6
mov DL, BYTE PTR [ECX + EBX]
// save bits 18..23
and AL, $3F
xor AH, AH
mov DH, BYTE PTR [ECX + EAX]
mov AX, DX
// store the last two bytes of the destination quadruple
STOSW
dec ByThrees
jnz @@LoopStart
@@LeftOver:
// there are up to two more bytes to encode
cmp LeftOver, 0
jz @@Done
// clear result
xor EAX, EAX
xor EBX, EBX
xor EDX, EDX
// get left over 1
LODSB
// load the first six bits
shl AX, 6
mov BL, AH
// save them
mov DL, BYTE PTR [ECX + EBX]
// another byte ?
dec LeftOver
jz @@SaveOne
// save remaining two bits
shl AX, 2
and AH, $03
// get left over 2
LODSB
// load next 4 bits
shl AX, 4
mov BL, AH
// save all 6 bits
mov DH, BYTE PTR [ECX + EBX]
shl EDX, 16
// save last 4 bits
shr AL, 2
mov BL, AL
// save them
mov DL, BYTE PTR [ECX + EBX]
// load base 64 'no more data flag'
mov DH, Base64Filler
jmp @@WriteLast4
@@SaveOne:
// adjust the last two bits
shr AL, 2
mov BL, AL
// save them
mov DH, BYTE PTR [ECX + EBX]
shl EDX, 16
// load base 64 'no more data flags'
mov DH, Base64Filler
mov DL, Base64Filler
// ignore jump, as jump reference is next line !
// jmp @@WriteLast4
@@WriteLast4:
// load and adjust result
mov EAX, EDX
ror EAX, 16
// save it to destination
STOSD
@@Done:
end;
{$IFDEF SpeedDecode}
procedure Base64Decode(const InBuffer; InSize: Cardinal; var OutBuffer);
overload; register;
{$ENDIF}
{$IFDEF ValidityCheck}
function Base64Decode(const InBuffer; InSize: Cardinal; var OutBuffer):
Boolean; overload; register;
{$ENDIF}
const
{$IFDEF SpeedDecode}
cBase64Codec: array[0..127] of Byte =
{$ENDIF}
{$IFDEF ValidityCheck}
cBase64Codec: array[0..255] of Byte =
{$ENDIF}
(
$FF, $FF, $FF, $FF, $FF, {005>} $FF, $FF, $FF, $FF, $FF, // 000..009
$FF, $FF, $FF, $FF, $FF, {015>} $FF, $FF, $FF, $FF, $FF, // 010..019
$FF, $FF, $FF, $FF, $FF, {025>} $FF, $FF, $FF, $FF, $FF, // 020..029
$FF, $FF, $FF, $FF, $FF, {035>} $FF, $FF, $FF, $FF, $FF, // 030..039
$FF, $FF, $FF, $3E, $FF, {045>} $FF, $FF, $3F, $34, $35, // 040..049
$36, $37, $38, $39, $3A, {055>} $3B, $3C, $3D, $FF, $FF, // 050..059
$FF, $FF, $FF, $FF, $FF, {065>} $00, $01, $02, $03, $04, // 060..069
$05, $06, $07, $08, $09, {075>} $0A, $0B, $0C, $0D, $0E, // 070..079
$0F, $10, $11, $12, $13, {085>} $14, $15, $16, $17, $18, // 080..089
$19, $FF, $FF, $FF, $FF, {095>} $FF, $FF, $1A, $1B, $1C, // 090..099
$1D, $1E, $1F, $20, $21, {105>} $22, $23, $24, $25, $26, // 100..109
$27, $28, $29, $2A, $2B, {115>} $2C, $2D, $2E, $2F, $30, // 110..119
$31, $32, $33, $FF, $FF, {125>} $FF, $FF, $FF // 120..127
{$IFDEF ValidityCheck}
{125>} , $FF, $FF, // 128..129
$FF, $FF, $FF, $FF, $FF, {135>} $FF, $FF, $FF, $FF, $FF, // 130..139
$FF, $FF, $FF, $FF, $FF, {145>} $FF, $FF, $FF, $FF, $FF, // 140..149
$FF, $FF, $FF, $FF, $FF, {155>} $FF, $FF, $FF, $FF, $FF, // 150..159
$FF, $FF, $FF, $FF, $FF, {165>} $FF, $FF, $FF, $FF, $FF, // 160..169
$FF, $FF, $FF, $FF, $FF, {175>} $FF, $FF, $FF, $FF, $FF, // 170..179
$FF, $FF, $FF, $FF, $FF, {185>} $FF, $FF, $FF, $FF, $FF, // 180..189
$FF, $FF, $FF, $FF, $FF, {195>} $FF, $FF, $FF, $FF, $FF, // 190..199
$FF, $FF, $FF, $FF, $FF, {205>} $FF, $FF, $FF, $FF, $FF, // 200..209
$FF, $FF, $FF, $FF, $FF, {215>} $FF, $FF, $FF, $FF, $FF, // 210..219
$FF, $FF, $FF, $FF, $FF, {225>} $FF, $FF, $FF, $FF, $FF, // 220..229
$FF, $FF, $FF, $FF, $FF, {235>} $FF, $FF, $FF, $FF, $FF, // 230..239
$FF, $FF, $FF, $FF, $FF, {245>} $FF, $FF, $FF, $FF, $FF, // 240..249
$FF, $FF, $FF, $FF, $FF, {255>} $FF // 250..255
{$ENDIF}
);
asm
push EBX
mov ESI, [EAX]
mov EDI, [ECX]
{$IFDEF ValidityCheck}
mov EAX, InSize
and EAX, $03
cmp EAX, $00
jz @@DecodeStart
jmp @@ErrorDone
@@DecodeStart:
{$ENDIF}
mov EAX, InSize
shr EAX, 2
jz @@Done
lea ECX, cBase64Codec[0]
xor EBX, EBX
dec EAX
jz @@LeftOver
push EBP
mov EBP, EAX
@@LoopStart:
// load four bytes into EAX
LODSD
// save them to EDX as AX is used to store results
mov EDX, EAX
// get bits 0..5
mov BL, DL
// decode
mov AH, BYTE PTR [ECX + EBX]
{$IFDEF ValidityCheck}
// check valid code
cmp AH, $FF
jz @@ErrorDoneAndPopEBP
{$ENDIF}
// get bits 6..11
mov BL, DH
// decode
mov AL, BYTE PTR [ECX + EBX]
{$IFDEF ValidityCheck}
// check valid code
cmp AL, $FF
jz @@ErrorDoneAndPopEBP
{$ENDIF}
// align last 6 bits
shl AL, 2
// get first 8 bits
ror AX, 6
// store first byte
STOSB
// align remaining 4 bits
shr AX, 12
// get next two bytes from source quad
shr EDX, 16
// load bits 12..17
mov BL, DL
// decode
mov AH, BYTE PTR [ECX + EBX]
{$IFDEF ValidityCheck}
// check valid code
cmp AH, $FF
jz @@ErrorDoneAndPopEBP
{$ENDIF}
// align ...
shl AH, 2
// ... and adjust
rol AX, 4
// get last bits 18..23
mov BL, DH
// decord
mov BL, BYTE PTR [ECX + EBX]
{$IFDEF ValidityCheck}
// check valid code
cmp BL, $FF
jz @@ErrorDoneAndPopEBP
{$ENDIF}
// enter in destination word
or AH, BL
// and store to destination
STOSW
// more coming ?
dec EBP
jnz @@LoopStart
pop EBP
// no
// last four bytes are handled separately, as special checking is needed
// on the last two bytes (may be end of data signals '=' or '==')
@@LeftOver:
// get the last four bytes
LODSD
// save them to EDX as AX is used to store results
mov EDX, EAX
// get bits 0..5
mov BL, DL
// decode
mov AH, BYTE PTR [ECX + EBX]
{$IFDEF ValidityCheck}
// check valid code
cmp AH, $FF
jz @@ErrorDone
{$ENDIF}
// get bits 6..11
mov BL, DH
// decode
mov AL, BYTE PTR [ECX + EBX]
{$IFDEF ValidityCheck}
// check valid code
cmp AL, $FF
jz @@ErrorDone
{$ENDIF}
// align last 6 bits
shl AL, 2
// get first 8 bits
ror AX, 6
// store first byte
STOSB
// get next two bytes from source quad
shr EDX, 16
// check DL for "end of data signal"
cmp DL, Base64Filler
jz @@SuccessDone
// align remaining 4 bits
shr AX, 12
// load bits 12..17
mov BL, DL
// decode
mov AH, BYTE PTR [ECX + EBX]
{$IFDEF ValidityCheck}
// check valid code
cmp AH, $FF
jz @@ErrorDone
{$ENDIF}
// align ...
shl AH, 2
// ... and adjust
rol AX, 4
// store second byte
STOSB
// check DH for "end of data signal"
cmp DH, Base64Filler
jz @@SuccessDone
// get last bits 18..23
mov BL, DH
// decord
mov BL, BYTE PTR [ECX + EBX]
{$IFDEF ValidityCheck}
// check valid code
cmp BL, $FF
jz @@ErrorDone
{$ENDIF}
// enter in destination word
or AH, BL
// AH - AL for saving last byte
mov AL, AH
// store third byte
STOSB
@@SuccessDone:
{$IFDEF ValidityCheck}
mov Result, $01
jmp @@Done
@@ErrorDoneAndPopEBP:
pop EBP
@@ErrorDone:
mov Result, $00
{$ENDIF}
@@Done:
pop EBX
end;
procedure Base64Encode(const InText: PAnsiChar; var OutText: PAnsiChar);
var
InSize, OutSize: Cardinal;
begin
// get size of source
InSize := Length(InText);
// calculate size for destination
OutSize := CalcEncodedSize(InSize);
// reserve memory
OutText := StrAlloc(Succ(OutSize));
OutText[OutSize] := #0;
// encode !
Base64Encode(InText, InSize, OutText);
end;
procedure Base64Encode(const InText: AnsiString; var OutText: AnsiString);
overload;
var
InSize, OutSize: Cardinal;
PIn, POut: Pointer;
begin
// get size of source
InSize := Length(InText);
// calculate size for destination
OutSize := CalcEncodedSize(InSize);
// prepare string length to fit result data
SetLength(OutText, OutSize);
PIn := @InText[1];
POut := @OutText[1];
// encode !
Base64Encode(PIn, InSize, POut);
end;
procedure Base64Decode(const InText: PAnsiChar; var OutText: PAnsiChar);
overload;
var
InSize, OutSize: Cardinal;
begin
// get size of source
InSize := Length(InText);
// calculate size for destination
OutSize := CalcDecodedSize(InText, InSize);
// reserve memory
OutText := StrAlloc(Succ(OutSize));
OutText[OutSize] := #0;
// encode !
{$IFDEF SpeedDecode}
Base64Decode(InText, InSize, OutText);
{$ENDIF}
{$IFDEF ValidityCheck}
if not Base64Decode(InText, InSize, OutText) then
OutText[0] := #0;
{$ENDIF}
end;
procedure Base64Decode(const InText: AnsiString; var OutText: AnsiString);
overload;
var
InSize, OutSize: Cardinal;
PIn, POut: Pointer;
begin
// get size of source
InSize := Length(InText);
// calculate size for destination
PIn := @InText[1];
OutSize := CalcDecodedSize(PIn, InSize);
// prepare string length to fit result data
SetLength(OutText, OutSize);
FillChar(OutText[1], OutSize, '.');
POut := @OutText[1];
// encode !
{$IFDEF SpeedDecode}
Base64Decode(PIn, InSize, POut);
{$ENDIF}
{$IFDEF ValidityCheck}
if not Base64Decode(PIn, InSize, POut) then
SetLength(OutText, 0);
{$ENDIF}
end;
end. |
|
... .... |
 Jeder Mensch lebt praktisch in seiner eigenen, privaten Welt. Kommunikation bedeutet zwischen diesen Welten Brücken zu bauen.
CodeGear Associate Evangelist
Zuletzt bearbeitet von sakura am 09.06.2004, 15:12, insgesamt 8-mal bearbeitet. |
 |
|
|
|
| |
| Luckie |
#2| Verfasst am: 05.10.2002, 16:34 Titel: |
|
 |
 |
|
Moderator Status: offline Beiträge: 30.064 angemeldet: 29.05.2002 Delphi 2006 Professional

|
Versuch es mal damit:
| Delphi-Quellcode: | markieren | function StrAlloc(Size: Cardinal): PChar;
begin
Inc(Size, SizeOf(Cardinal));
GetMem(Result, Size);
Cardinal(Pointer(Result)^) := Size;
Inc(Result, SizeOf(Cardinal));
end; |
| |
 Programmieren ist ein Rennen zwischen den Softwareentwicklern, die versuchen größere und bessere idiotensichere Programme zu schreiben und dem Universum, welches versucht größere und bessere Idioten zu produzieren. Zur Zeit liegt das Universum in Führung.
Zuletzt bearbeitet am 29.11.2002, 22:31, insgesamt 1-mal bearbeitet. |
 |
|
|
|
| |
|
|
 |
|
 |
| |
|
|
|
 |