Subversion Repositories decoder

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 daniel-mar 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.