const
XX: Array[0..63] ofChar =
'+-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
procedureTriplet2Kwartet( constTriplet: TTriplet; varKwartet: TKwartet);
var
i: Integer;
begin
Kwartet[0] := (Triplet[0] SHR2);
Kwartet[1] := ((Triplet[0] SHL4) AND$30) +
((Triplet[1] SHR4) AND$0F);
Kwartet[2] := ((Triplet[1] SHL2) AND$3C) +
((Triplet[2] SHR6) AND$03);
Kwartet[3] := (Triplet[2] AND$3F);
fori:=0 to3 do
ifKwartet[i] = 0 then Kwartet[i] := $40 + Ord(SP)
elseInc(Kwartet[i],Ord(SP));
ifXXCode then
fori:=0 to3 do Kwartet[i] := Ord(XX[(Kwartet[i] - Ord(SP)) mod$40])
end {Triplet2Kwartet} ;
Последние несколько строк новые для процедуры Triplet2Kwartet и мы используем набор символов XXencode для возврата правильно закодированных символов. Помните, что UUEncode возвращает индекс кодированного символа, после чего мы к нему добавляем код #32, так что если XXencode используется после преобразования в UUEncode, то мы должны вычесть 32 и использовать результат как индекс в таблицу символов XXencode.
То же самое относится и к процедуре Kwartet2Triplet, где мы должны преобразовать XXencode символы перед использованием алгоритма UUdecode (заметим, что мы теперь не передаем Kwartet как const).
procedureKwartet2Triplet(Kwartet: TKwartet; varTriplet: TTriplet);
var
i: Integer;
begin
ifXXCode then
begin
fori:=0 to3 do
begin
caseChr(Kwartet[i]) of
'+': Kwartet[i] := 0 + Ord(SP);
'-': Kwartet[i] := 1 + Ord(SP);
'0'..'9': Kwartet[i] := 2 + Kwartet[i]
- Ord('0') + Ord(SP);
'A'..'Z': Kwartet[i] := 12 + Kwartet[i]
- Ord('A') + Ord(SP);
'a'..'z': Kwartet[i] := 38 + Kwartet[i]
- Ord('a') + Ord(SP)
end
end
end;
Triplet[0] := ((Kwartet[0] - Ord(SP)) SHL2) +
(((Kwartet[1] - Ord(SP)) AND$30) SHR4);
Triplet[1] := (((Kwartet[1] - Ord(SP)) AND$0F) SHL4) +
(((Kwartet[2] - Ord(SP)) AND$3C) SHR2);
Triplet[2] := (((Kwartet[2] - Ord(SP)) AND$03) SHL6) +
((Kwartet[3] - Ord(SP)) AND$3F)
end{Kwartet2Triplet};
Заметим, что в новой версии этих процедур используется глобальная переменная XXCode логического типа для определения типа кодирования.
Алгоритм кодирования Base64 отличается от алгоритмов UUencode и XXencode тем, что в нем не используется первый символ как индикатор длины. Общее то что используется алгоритм преобразования триплетов в квартеты с помощью 64 байтной таблицы преобразования.
Набор символов Base64 |
0 A |
8 I |
16 Q |
24 Y |
32 g |
40 o |
48 w |
56 4 |
1 B |
9 J |
17 R |
25 Z |
33 h |
41 p |
49 x |
57 5 |
2 C |
10 K |
18 S |
26 a |
34 I |
42 q |
50 y |
58 6 |
3 D |
11 L |
19 T |
27 b |
35 j |
43 r |
51 z |
59 7 |
4 E |
12 M |
20 U |
28 c |
36 k |
44 s |
52 0 |
60 8 |
5 F |
13 N |
21 V |
29 d |
37 l |
45 t |
53 1 |
61 9 |
6 G |
14 O |
22 W |
30 e |
38 m |
46 u |
54 2 |
62 + |
7 H |
15 P |
23 X |
31 f |
39 n |
47 v |
55 3 |
63 / |
Подобно набору символов XXencode, набор символов Base64 не является подмножеством набора символов ASCII.
Это означает, что мы должны добавить массив преобразования в набор символов Base64 и также преобразовать процедуры Triplet2Kwartet и Kwartet2Triplet для поддержки данного алгоритма:
const
B64: Array[0..63] of Char =
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
procedure Triplet2Kwartet(Const Triplet: TTriplet; var Kwartet: TKwartet);
var
i: Integer;
begin
Kwartet[0] := (Triplet[0] SHR 2);
Kwartet[1] := ((Triplet[0] SHL 4) AND $30) +
((Triplet[1] SHR 4) AND $0F);
Kwartet[2] := ((Triplet[1] SHL 2) AND $3C) +
((Triplet[2] SHR 6) AND $03);
Kwartet[3] := (Triplet[2] AND $3F);
for i:=0 to 3 do
if Kwartet[i] = 0 then Kwartet[i] := $40 + Ord(SP)
else Inc(Kwartet[i],Ord(SP));
if Base64 then
for i:=0 to 3 do
Kwartet[i] := Ord(B64[(Kwartet[i] - Ord(SP)) mod $40])
else
if XXCode then
for i:=0 to 3 do
Kwartet[i] := Ord(XX[(Kwartet[i] - Ord(SP)) mod $40])
end {Triplet2Kwartet} ;
procedure Kwartet2Triplet(Kwartet: TKwartet; var Triplet: TTriplet);
var
i: Integer;
begin
if Base64 then
begin
for i:=0 to 3 do
begin
case Chr(Kwartet[i]) of
'A'..'Z': Kwartet[i] := 0 + Kwartet[i]
- Ord('A') + Ord(SP);
Читать дальше