Articles   Members Online:
-Article/Tip Search
-News Group Search over 21 Million news group articles.
-Delphi/Pascal
-CBuilder/C++
-C#Builder/C#
-JBuilder/Java
-Kylix
Member Area
-Home
-Account Center
-Top 10 NEW!!
-Submit Article/Tip
-Forums Upgraded!!
-My Articles
-Edit Information
-Login/Logout
-Become a Member
-Why sign up!
-Newsletter
-Chat Online!
-Indexes NEW!!
Employment
-Build your resume
-Find a job
-Post a job
-Resume Search
Contacts
-Contacts
-Feedbacks
-Link to us
-Privacy/Disclaimer
Embarcadero
Visit Embarcadero
Embarcadero Community
JEDI
Links
Base64 (MIME) Encode and Decode Turn on/off line numbers in source code. Switch to Orginial background IDE or DSP color Comment or reply to this aritlce/tip for discussion. Bookmark this article to my favorite article(s). Print this article
29-May-03
Category
Internet / Web
Language
Delphi 5.x
Views
229
User Rating
No Votes
# Votes
0
Replies
0
Publisher:
DSP, Administrator
Reference URL:
DKB
			Author: Daniel Wischnewski

This article gives you two routines allowing for fast encoding and decoding in and 
out of the MIME format.

Answer:

I have written the following unit to replace the INDY TIdEncoderMIME and 
TIdDecoderMIME components. This "Codec" is used in Email-Software, primarely. 

First reason was the lack of speed of these components. Second reason was, that 
they are components and therefore require the VCL - an heavy extra load on 
otherwise nonVCL systems. 

Both routines are written in Assembler and overloaded by different versions 
allowing for easy access. 

I am sure, some of your are able to increase the speed even some more. Please let 
me know. Thanks. 

I have introduced a compiler switch to switch between a fast decoding mode and a 
more secure decoding mode. It is up to you, which you like to use. I recomend using 
the more secure mode, especially if the user is required to work with the encoded 
data. 
1   
2   {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
3    *
4    * Unit Name : uBase64Codec
5    * Author    : Daniel Wischnewski
6    * Copyright : Copyright © 2001-2003 by gate(n)etwork GmbH. All Rights Reserved.
7    * Creator   : Daniel Wischnewski
8    * Contact   : Daniel Wischnewski (e-mail: delphi3000(at)wischnewski.tv);
9    *
10   * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
11  
12  //                               * * * License * * *
13  //
14  // The contents of this file are used with permission, subject to the Mozilla
15  // Public License Version 1.1 (the "License"); you may not use this file except
16  // in compliance with the License. You may obtain a copy of the License at
17  //
18  //                       http://www.mozilla.org/MPL/MPL-1.1.html
19  //
20  // Software distributed under the License is distributed on an "AS IS" basis,
21  // WITHOUT WARRANTY OF ANY KIND, either express or  implied. See the License for
22  // the specific language governing rights and limitations under the License.
23  //
24  
25  //                               * * * My Wish * * *
26  //
27  // If you come to use this unit for your work, I would like to know about it.
28  // Drop me an e-mail and let me know how it worked out for you. If you wish, you
29  // can send me a copy of your work. No obligations!
30  // My e-mail address: delphi3000(at)wischnewski.tv
31  //
32  
33  //                               * * * History * * *
34  //
35  // Version 1.0 (Oct-10 2002)
36  //    first published on Delphi-PRAXiS (www.delphipraxis.net)
37  //
38  // Version 1.1 (May-13 2003)
39  //    introduced a compiler switch (SpeedDecode) to switch between a faster
40  //    decoding variant (prior version) and a litte less fast, but secure variant
41  //    to work around bad formatted data (decoding only!)
42  //
43  
44  unit Base64;
45  
46  interface
47  
48  // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
49  // !! THE COMPILER SWITCH MAY BE USED TO ADJUST THE BEHAVIOR !!
50  // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
51  
52  // enable "SpeedDecode"
53  //     the switch to gain speed while decoding the message, however, the codec
54  //     will raise different exceptions/access violations or invalid output if
55  //     the incoming data is invalid or missized.
56  
57  // disable "SpeedDecode"
58  //     the switch to enable a data check, that will scan the data to decode to
59  //     be valid. This method is to be used if you cannot guarantee to validity
60  //     of the data to be decoded.
61  
62  {.DEFINE SpeedDecode}
63  
64  {$IFNDEF SpeedDecode}
65  {$DEFINE ValidityCheck}
66  {$ENDIF}
67  
68  uses SysUtils;
69  
70  // codiert einen String in die zugehörige Base64-Darstellung
71  function Base64Encode(const InText: AnsiString): AnsiString; overload;
72  // decodiert die Base64-Darstellung eines Strings in den zugehörigen String
73  function Base64Decode(const InText: AnsiString): AnsiString; overload;
74  
75  // bestimmt die Größe der Base64-Darstellung
76  function CalcEncodedSize(InSize: Cardinal): Cardinal;
77  // bestimmt die Größe der binären Darstellung
78  function CalcDecodedSize(const InBuffer; InSize: Cardinal): Cardinal;
79  
80  // codiert einen Buffer in die zugehörige Base64-Darstellung
81  procedure Base64Encode(const InBuffer; InSize: Cardinal; var OutBuffer); overload;
82    register;
83  // decodiert die Base64-Darstellung in einen Buffer
84  {$IFDEF SpeedDecode}
85  procedure Base64Decode(const InBuffer; InSize: Cardinal; var OutBuffer); overload;
86    register;
87  {$ENDIF}
88  {$IFDEF ValidityCheck}
89  function Base64Decode(const InBuffer; InSize: Cardinal; var OutBuffer): Boolean;
90    overload; register;
91  {$ENDIF}
92  
93  // codiert einen String in die zugehörige Base64-Darstellung
94  procedure Base64Encode(const InText: PAnsiChar; var OutText: PAnsiChar); overload;
95  // decodiert die Base64-Darstellung eines Strings in den zugehörigen String
96  procedure Base64Decode(const InText: PAnsiChar; var OutText: PAnsiChar); overload;
97  
98  // codiert einen String in die zugehörige Base64-Darstellung
99  procedure Base64Encode(const InText: AnsiString; var OutText: AnsiString); overload;
100 // decodiert die Base64-Darstellung eines Strings in den zugehörigen String
101 procedure Base64Decode(const InText: AnsiString; var OutText: AnsiString); overload;
102 
103 implementation
104 
105 const
106   cBase64Codec: array[0..63] of AnsiChar =
107   'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
108   Base64Filler = '=';
109 
110 function Base64Encode(const InText: string): string; overload;
111 begin
112   Base64Encode(InText, Result);
113 end;
114 
115 function Base64Decode(const InText: string): string; overload;
116 begin
117   Base64Decode(InText, Result);
118 end;
119 
120 function CalcEncodedSize(InSize: Cardinal): Cardinal;
121 begin
122   // no buffers passed along, calculate outbuffer size needed
123   Result := (InSize div 3) shl 2;
124   if ((InSize mod 3) > 0) then
125     Inc(Result, 4);
126 end;
127 
128 function CalcDecodedSize(const InBuffer; InSize: Cardinal): Cardinal;
129 type
130   BA = array of Byte;
131 begin
132   Result := 0;
133   if InSize = 0 then
134     Exit;
135   if InSize mod 4 <> 0 then
136     Exit;
137   Result := InSize div 4 * 3;
138   if (BA(InBuffer)[InSize - 2] = Ord(Base64Filler)) then
139     Dec(Result, 2)
140   else if BA(InBuffer)[InSize - 1] = Ord(Base64Filler) then
141     Dec(Result);
142 end;
143 
144 procedure Base64Encode(const InBuffer; InSize: Cardinal; var OutBuffer
145   ); register;
146 var
147   ByThrees, LeftOver: Cardinal;
148   // reset in- and outbytes positions
149 asm
150   // load addresses for source and destination
151   // PBYTE(InBuffer);
152   mov  ESI, [EAX]
153   // PBYTE(OutBuffer);
154   mov  EDI, [ECX]
155   // ByThrees := InSize div 3;
156   // LeftOver := InSize mod 3;
157   // load InSize (stored in EBX)
158   mov  EAX, EBX
159   // load 3
160   mov  ECX, $03
161   // clear upper 32 bits
162   xor  EDX, EDX
163   // divide by ECX
164   div  ECX
165   // save result
166   mov  ByThrees, EAX
167   // save remainder
168   mov  LeftOver, EDX
169   // load addresses
170   lea  ECX, cBase64Codec[0]
171   // while I < ByThrees do
172   // begin
173   xor  EAX, EAX
174   xor  EBX, EBX
175   xor  EDX, EDX
176   cmp  ByThrees, 0
177   jz   @@LeftOver
178   @@LoopStart:
179     // load the first two bytes of the source triplet
180     LODSW
181     // write Bits 0..5 to destination
182     mov  BL, AL
183     shr  BL, 2
184     mov  DL, BYTE PTR [ECX + EBX]
185     // save the Bits 12..15 for later use [1]
186     mov  BH, AH
187     and  BH, $0F
188     // save Bits 6..11
189     rol  AX, 4
190     and  AX, $3F
191     mov  DH, BYTE PTR [ECX + EAX]
192     mov  AX, DX
193     // store the first two bytes of the destination quadruple
194     STOSW
195     // laod last byte (Bits 16..23) of the source triplet
196     LODSB
197     // extend bits 12..15 [1] with Bits 16..17 and save them
198     mov  BL, AL
199     shr  BX, 6
200     mov  DL, BYTE PTR [ECX + EBX]
201     // save bits 18..23
202     and  AL, $3F
203     xor  AH, AH
204     mov  DH, BYTE PTR [ECX + EAX]
205     mov  AX, DX
206     // store the last two bytes of the destination quadruple
207     STOSW
208     dec  ByThrees
209   jnz  @@LoopStart
210   @@LeftOver:
211   // there are up to two more bytes to encode
212   cmp  LeftOver, 0
213   jz   @@Done
214   // clear result
215   xor  EAX, EAX
216   xor  EBX, EBX
217   xor  EDX, EDX
218   // get left over 1
219   LODSB
220   // load the first six bits
221   shl  AX, 6
222   mov  BL, AH
223   // save them
224   mov  DL, BYTE PTR [ECX + EBX]
225   // another byte ?
226   dec  LeftOver
227   jz   @@SaveOne
228   // save remaining two bits
229   shl  AX, 2
230   and  AH, $03
231   // get left over 2
232   LODSB
233   // load next 4 bits
234   shl  AX, 4
235   mov  BL, AH
236   // save all 6 bits
237   mov  DH, BYTE PTR [ECX + EBX]
238   shl  EDX, 16
239   // save last 4 bits
240   shr  AL, 2
241   mov  BL, AL
242   // save them
243   mov  DL, BYTE PTR [ECX + EBX]
244   // load base 64 'no more data flag'
245   mov  DH, Base64Filler
246   jmp  @@WriteLast4
247   @@SaveOne:
248   // adjust the last two bits
249   shr  AL, 2
250   mov  BL, AL
251   // save them
252   mov  DH, BYTE PTR [ECX + EBX]
253   shl  EDX, 16
254   // load base 64 'no more data flags'
255   mov  DH, Base64Filler
256   mov  DL, Base64Filler
257   // ignore jump, as jump reference is next line !
258   // jmp  @@WriteLast4
259   @@WriteLast4:
260     // load and adjust result
261     mov  EAX, EDX
262     ror EAX, 16
263     // save it to destination
264     STOSD
265   @@Done:
266 end;
267 
268 {$IFDEF SpeedDecode}
269 
270 procedure Base64Decode(const InBuffer; InSize: Cardinal; var OutBuffer);
271   overload; register;
272 {$ENDIF}
273 {$IFDEF ValidityCheck}
274   function Base64Decode(const InBuffer; InSize: Cardinal; var OutBuffer):
275       Boolean; overload; register;
276   {$ENDIF}
277   const
278   {$IFDEF SpeedDecode}
279     cBase64Codec: array[0..127] of Byte =
280   {$ENDIF}
281   {$IFDEF ValidityCheck}
282     cBase64Codec: array[0..255] of Byte =
283   {$ENDIF}
284     (
285       $FF, $FF, $FF, $FF, $FF, {005>} $FF, $FF, $FF, $FF, $FF, // 000..009
286       $FF, $FF, $FF, $FF, $FF, {015>} $FF, $FF, $FF, $FF, $FF, // 010..019
287       $FF, $FF, $FF, $FF, $FF, {025>} $FF, $FF, $FF, $FF, $FF, // 020..029
288       $FF, $FF, $FF, $FF, $FF, {035>} $FF, $FF, $FF, $FF, $FF, // 030..039
289       $FF, $FF, $FF, $3E, $FF, {045>} $FF, $FF, $3F, $34, $35, // 040..049
290       $36, $37, $38, $39, $3A, {055>} $3B, $3C, $3D, $FF, $FF, // 050..059
291       $FF, $FF, $FF, $FF, $FF, {065>} $00, $01, $02, $03, $04, // 060..069
292       $05, $06, $07, $08, $09, {075>} $0A, $0B, $0C, $0D, $0E, // 070..079
293       $0F, $10, $11, $12, $13, {085>} $14, $15, $16, $17, $18, // 080..089
294       $19, $FF, $FF, $FF, $FF, {095>} $FF, $FF, $1A, $1B, $1C, // 090..099
295       $1D, $1E, $1F, $20, $21, {105>} $22, $23, $24, $25, $26, // 100..109
296       $27, $28, $29, $2A, $2B, {115>} $2C, $2D, $2E, $2F, $30, // 110..119
297       $31, $32, $33, $FF, $FF, {125>} $FF, $FF, $FF // 120..127
298 
299   {$IFDEF ValidityCheck}
300       {125>}, $FF, $FF, // 128..129
301       $FF, $FF, $FF, $FF, $FF, {135>} $FF, $FF, $FF, $FF, $FF, // 130..139
302       $FF, $FF, $FF, $FF, $FF, {145>} $FF, $FF, $FF, $FF, $FF, // 140..149
303       $FF, $FF, $FF, $FF, $FF, {155>} $FF, $FF, $FF, $FF, $FF, // 150..159
304       $FF, $FF, $FF, $FF, $FF, {165>} $FF, $FF, $FF, $FF, $FF, // 160..169
305       $FF, $FF, $FF, $FF, $FF, {175>} $FF, $FF, $FF, $FF, $FF, // 170..179
306       $FF, $FF, $FF, $FF, $FF, {185>} $FF, $FF, $FF, $FF, $FF, // 180..189
307       $FF, $FF, $FF, $FF, $FF, {195>} $FF, $FF, $FF, $FF, $FF, // 190..199
308       $FF, $FF, $FF, $FF, $FF, {205>} $FF, $FF, $FF, $FF, $FF, // 200..209
309       $FF, $FF, $FF, $FF, $FF, {215>} $FF, $FF, $FF, $FF, $FF, // 210..219
310       $FF, $FF, $FF, $FF, $FF, {225>} $FF, $FF, $FF, $FF, $FF, // 220..229
311       $FF, $FF, $FF, $FF, $FF, {235>} $FF, $FF, $FF, $FF, $FF, // 230..239
312       $FF, $FF, $FF, $FF, $FF, {245>} $FF, $FF, $FF, $FF, $FF, // 240..249
313       $FF, $FF, $FF, $FF, $FF, {255>} $FF // 250..255
314   {$ENDIF}
315       );
316   asm
317   push EBX
318   mov  ESI, [EAX]
319   mov  EDI, [ECX]
320   {$IFDEF ValidityCheck}
321     mov  EAX, InSize
322     and  EAX, $03
323     cmp  EAX, $00
324     jz   @@DecodeStart
325     jmp  @@ErrorDone
326     @@DecodeStart:
327   {$ENDIF}
328   mov  EAX, InSize
329   shr  EAX, 2
330   jz   @@Done
331   lea  ECX, cBase64Codec[0]
332   xor  EBX, EBX
333   dec  EAX
334   jz   @@LeftOver
335   push EBP
336   mov  EBP, EAX
337   @@LoopStart:
338     // load four bytes into EAX
339     LODSD
340     // save them to EDX as AX is used to store results
341     mov  EDX, EAX
342     // get bits 0..5
343     mov  BL, DL
344     // decode
345     mov  AH, BYTE PTR [ECX + EBX]
346     {$IFDEF ValidityCheck}
347       // check valid code
348       cmp  AH, $FF
349       jz   @@ErrorDoneAndPopEBP
350     {$ENDIF}
351     // get bits 6..11
352     mov  BL, DH
353     // decode
354     mov  AL, BYTE PTR [ECX + EBX]
355     {$IFDEF ValidityCheck}
356       // check valid code
357       cmp  AL, $FF
358       jz   @@ErrorDoneAndPopEBP
359     {$ENDIF}
360     // align last 6 bits
361     shl  AL, 2
362     // get first 8 bits
363     ror  AX, 6
364     // store first byte
365     STOSB
366     // align remaining 4 bits
367     shr  AX, 12
368     // get next two bytes from source quad
369     shr  EDX, 16
370     // load bits 12..17
371     mov  BL, DL
372     // decode
373     mov  AH, BYTE PTR [ECX + EBX]
374     {$IFDEF ValidityCheck}
375       // check valid code
376       cmp  AH, $FF
377       jz   @@ErrorDoneAndPopEBP
378     {$ENDIF}
379     // align ...
380     shl  AH, 2
381     // ... and adjust
382     rol  AX, 4
383     // get last bits 18..23
384     mov  BL, DH
385     // decord
386     mov  BL, BYTE PTR [ECX + EBX]
387     {$IFDEF ValidityCheck}
388       // check valid code
389       cmp  BL, $FF
390       jz   @@ErrorDoneAndPopEBP
391     {$ENDIF}
392     // enter in destination word
393     or   AH, BL
394     // and store to destination
395     STOSW
396     // more coming ?
397     dec  EBP
398   jnz  @@LoopStart
399   pop  EBP
400   // no
401   // last four bytes are handled separately, as special checking is needed
402   // on the last two bytes (may be end of data signals '=' or '==')
403   @@LeftOver:
404   // get the last four bytes
405   LODSD
406   // save them to EDX as AX is used to store results
407   mov  EDX, EAX
408   // get bits 0..5
409   mov  BL, DL
410   // decode
411   mov  AH, BYTE PTR [ECX + EBX]
412   {$IFDEF ValidityCheck}
413     // check valid code
414     cmp  AH, $FF
415     jz   @@ErrorDone
416   {$ENDIF}
417   // get bits 6..11
418   mov  BL, DH
419   // decode
420   mov  AL, BYTE PTR [ECX + EBX]
421   {$IFDEF ValidityCheck}
422     // check valid code
423     cmp  AL, $FF
424     jz   @@ErrorDone
425   {$ENDIF}
426   // align last 6 bits
427   shl  AL, 2
428   // get first 8 bits
429   ror  AX, 6
430   // store first byte
431   STOSB
432   // get next two bytes from source quad
433   shr  EDX, 16
434   // check DL for "end of data signal"
435   cmp  DL, Base64Filler
436   jz   @@SuccessDone
437   // align remaining 4 bits
438   shr  AX, 12
439   // load bits 12..17
440   mov  BL, DL
441   // decode
442   mov  AH, BYTE PTR [ECX + EBX]
443   {$IFDEF ValidityCheck}
444     // check valid code
445     cmp  AH, $FF
446     jz   @@ErrorDone
447   {$ENDIF}
448   // align ...
449   shl  AH, 2
450   // ... and adjust
451   rol  AX, 4
452   // store second byte
453   STOSB
454   // check DH for "end of data signal"
455   cmp  DH, Base64Filler
456   jz   @@SuccessDone
457   // get last bits 18..23
458   mov  BL, DH
459   // decord
460   mov  BL, BYTE PTR [ECX + EBX]
461   {$IFDEF ValidityCheck}
462     // check valid code
463     cmp  BL, $FF
464     jz   @@ErrorDone
465   {$ENDIF}
466   // enter in destination word
467   or   AH, BL
468   // AH - AL for saving last byte
469   mov  AL, AH
470   // store third byte
471   STOSB
472   @@SuccessDone:
473   {$IFDEF ValidityCheck}
474     mov  Result, $01
475     jmp  @@Done
476     @@ErrorDoneAndPopEBP:
477     pop  EBP
478     @@ErrorDone:
479     mov  Result, $00
480   {$ENDIF}
481   @@Done:
482   pop  EBX
483   end;
484 
485   procedure Base64Encode(const InText: PAnsiChar; var OutText: PAnsiChar);
486   var
487     InSize, OutSize: Cardinal;
488   begin
489     // get size of source
490     InSize := Length(InText);
491     // calculate size for destination
492     OutSize := CalcEncodedSize(InSize);
493     // reserve memory
494     OutText := StrAlloc(Succ(OutSize));
495     OutText[OutSize] := #0;
496     // encode !
497     Base64Encode(InText, InSize, OutText);
498   end;
499 
500   procedure Base64Encode(const InText: AnsiString; var OutText: AnsiString);
501     overload;
502   var
503     InSize, OutSize: Cardinal;
504     PIn, POut: Pointer;
505   begin
506     // get size of source
507     InSize := Length(InText);
508     // calculate size for destination
509     OutSize := CalcEncodedSize(InSize);
510     // prepare string length to fit result data
511     SetLength(OutText, OutSize);
512     PIn := @InText[1];
513     POut := @OutText[1];
514     // encode !
515     Base64Encode(PIn, InSize, POut);
516   end;
517 
518   procedure Base64Decode(const InText: PAnsiChar; var OutText: PAnsiChar);
519     overload;
520   var
521     InSize, OutSize: Cardinal;
522   begin
523     // get size of source
524     InSize := Length(InText);
525     // calculate size for destination
526     OutSize := CalcDecodedSize(InText, InSize);
527     // reserve memory
528     OutText := StrAlloc(Succ(OutSize));
529     OutText[OutSize] := #0;
530     // encode !
531 {$IFDEF SpeedDecode}
532     Base64Decode(InText, InSize, OutText);
533 {$ENDIF}
534 {$IFDEF ValidityCheck}
535     if not Base64Decode(InText, InSize, OutText) then
536       OutText[0] := #0;
537 {$ENDIF}
538   end;
539 
540   procedure Base64Decode(const InText: AnsiString; var OutText: AnsiString);
541     overload;
542   var
543     InSize, OutSize: Cardinal;
544     PIn, POut: Pointer;
545   begin
546     // get size of source
547     InSize := Length(InText);
548     // calculate size for destination
549     PIn := @InText[1];
550     OutSize := CalcDecodedSize(PIn, InSize);
551     // prepare string length to fit result data
552     SetLength(OutText, OutSize);
553     FillChar(OutText[1], OutSize, '.');
554     POut := @OutText[1];
555     // encode !
556 {$IFDEF SpeedDecode}
557     Base64Decode(PIn, InSize, POut);
558 {$ENDIF}
559 {$IFDEF ValidityCheck}
560     if not Base64Decode(PIn, InSize, POut) then
561       SetLength(OutText, 0);
562 {$ENDIF}
563   end;
564 
565 end.


			
Vote: How useful do you find this Article/Tip?
Bad Excellent
1 2 3 4 5 6 7 8 9 10

 

Advertisement
Share this page
Advertisement
Download from Google

Copyright © Mendozi Enterprises LLC