Login | ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/decoder/trunk/INCLUDES/base64.pas
Revision: 2
Committed: Thu Nov 8 11:09:30 2018 UTC (23 months, 3 weeks ago) by daniel-marschall
Content type: text/x-pascal
File size: 17398 byte(s)
Log Message:
Published revision 01 March 2007 to SVN.
Added disclaimer.
Changed the license to Apache2.

File Contents

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