(*
+------------------------------------------------------------------------------+
|                                МОДУЛЬ                                        |
|                 для base64 кодирования и декодирования                       |
|           *************************************************                  |
|                                                                              |
| Суть base64-кодирования заключается в конвертации байтов в текст по принципу |
|  3 к 4.  Т.е. три 8-ми битных байта (размер 0-255) конвертируются в четыре   |
|  символа, код которых занимает 6 байтов (размер 0-63). Алфавит base64        |
|  состоит из 64 символов:                                                     |
|       ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/       |
|  где символ A имеет код 0, а символ / имеет код 63.                          |
|                                                                              |
| Пример. Имеем три числа 103, 193, 58. Их надо закодировать в base64 формат.  |
| 1. Берем первые 6 байтов первого числа (103) и записываем их в перый base64  |
|    6-ти битный код. Получаем число 25.                                       |
| 2. Берем оставшиеся 2 байта первого числа (103) и первые 4 байта второго     |
|    числа (193). Записываем их во второй base64 6-ти битный код. Получаем     |
|    число 60.                                                                 |
| 3. Берем оставшиеся 4 байта второго числа (193) и 2 первые байта третьего    |
|    числа (58). Записываем их в третий base64 6-ти битный код. Получаем       |
|    число 4.                                                                  |
| 4. Берем последние 6 байтов третьего числа (58) и записываем их в четвертый  |
|    base64 6-ти битный код. Получаем число 58.                                |
| 5. Обращаемся к base64 алфавиту:                                             |
|        номер позиции символа в стринге алфавита = base64-код + 1             |
|                                                                              |
|                 десятичное число:    103       193       58                  |
|                   двоичное число: 01100111  11000001  00111010               |
|    двоичный 6-ти бит. base64-код: 011001 111100 000100 111010                |
|       десятичный вид base64-кода:   25     60     4      58                  |
|                    base64 символ:   Z      8      E      6                   |
|                                                                              |
|  Что делать, если при чтении последних байтов из файла число байт составляет |
|   менее трех? В этом случае надо поступать так:                              |
|   1. Если считывает один байт, то в конец base64 квартета дописывается два   |
|   символа = (равно):                                                         |
|                       Ew==                                                   |
|   2. Если считывается два байт, то дописывается один символ равно:           |
|                       Ew6=                                                   |
|   3. Если считываются три символа, то ничего не дописывается:                |
|                      Ew6y                                                    |
|                                                                              |
|    Base64 имеет граничение:                                                  |
|  - длина base64 кодированной строки должна составлять не более 72 символов.  |
|                                                                              |
|                             Как использовать модуль.                         |
|                                                                              |
|1. Подключаем модуль Base64Unit к своему проекту                              |
|                                                                              |
|2. Кодирование                                                                |
|2.1 Заполняем переменную типа TBase64.ByteArr нужными байтами и указываем     |
|    в TBase64.ByteCount количество байт к кодированию                         |
|2.2 Вызываем функцию CodeBase64(TBase64), в результате получаем String        |
|    закодированный в формате base64                                           |
|2.3 При обработке кодированного base64 стринга не забываем, что его строка    |
|    должна составлять 72 символа.                                             |
|                                                                              |
|3. Декодирование                                                              |
|3.1 Вызываем функцию DecodeBase64, в качестве аргумента передаем четыре       |
|    символа base64 кодированной строки, в результате получаем декодирован-    |
|    ные байты в массиве TBase64.ByteArr и их количество в TBase64.ByteCount   |
|                                                                              |
| (c) 2002 Терехов А.В.                                                        |
|   http://www.inta.portal.ru/dark/index.html                                  |
|   mailto:dark@online.ru                                                      |
|                                                                              |
|
|       ***************************************************************        |
|  Вы можете использовать этот модуль по своему усмотрению, при условии        |
|                сохранения выше приведенного описания.                        |
|                                                                              |
+------------------------------------------------------------------------------+
*)

unit Base64Unit;

interface
Const
//base64 алфавит
base64ABC='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';

Type
TBase64 = Record //структура для работы с base64
ByteArr  : Array [0..2] Of Byte;//массив из трех байтов
ByteCount:Byte;                 //количество считанных байт
End;

//кодируем base64
Function CodeBase64(Base64:TBase64):String;
//декодируем base64
Function DecodeBase64(StringValue:String):TBase64;
//кодируем строку в Base64
Function StrToStrBase64(Value:String):String;
implementation
//==============================CodeBase64======================================
//кодируем base64
Function CodeBase64(Base64:TBase64):String;
Var
N,M:Byte;
Dest,        //результат - 6-ти битное число с base64-кодом
Sour:Byte;   //исходное 8-ми битное число
NextNum:Byte;// флаг-счетчик для начала работы со следующим 6-ти битным числом
Temp:Byte;   //вспомогательная переменная используется для проверки старшего байта
             //8-ми битного исходного числа
Begin {CodeBase64}
//обнуляем результат
Result:='';
//инициализируем флаг - "следущее 6-ти битное число"
NextNum:=1;
//обнуляем 6-ти битный результат
Dest:=0;
//будем работать с массивом из трех байтов
For N:=0 To 2 Do
Begin {For N}
//берем очередной байт-источник
Sour:=Base64.ByteArr[N];
//пройдемся по всем 8-ми битам байта источника
For M:=0 To 7 Do
Begin {For M}
//будем работать не с самим байтом источником, а с его копией
Temp:=Sour;
//делаем побитный сдвиг влево для байта-источника и байта-приемника
Temp:=Temp SHL M;
Dest:=Dest SHL 1;
//если старший бит байта-источника равен 1
If (Temp And 128) = 128 Then
//в байте приемнике устанавливаем младший бит в 1
Dest:=Dest Or 1;
//увеличиваем счетчик перехода к следующему байту-приемнику
Inc(NextNum);
//если обработаны все 6 битов числа-приемника
If NextNum > 6 Then
Begin {If NextNum}
//заполняем результат функции, добавляя к нему символ из строки base64-алфавита
//с кодом на 1 больше, чем Dest (base64 коды начинаются с 0, а код первого
//символа строки base64-алфавита 1).
Result:=Result+base64ABC[Dest+1];
//обнуляем счетчик обработанных бит 6-ти битного числа-премника
NextNum:=1;
//обнуляем число-приемник
Dest:=0;
End; {If NextNum}
End; {For M}
End;{For N}
//добавим конечный знак = (равно)
//один знак, если обрабатываются два байта и два знака, если обрабатывается 1 байт
//не забываем, что кодированный стринг состоит из 4 символов
If Base64.ByteCount < 3 Then
For N:=0 To (2 - Base64.ByteCount) Do
Result[4-N]:='=';

End;  {CodeBase64}
//==============================CodeBase64======================================
//******************************************************************************
//================================DecodeBase64==================================
//декодируем base64
Function DecodeBase64(StringValue:String):TBase64;
Var
M,N:Integer;
Dest,           //6-ти битное число-источник
Sour:Byte;      //8-ми битный байт-приемник
NextNum:Byte;   //флаг-счетчик перехода к следующему 8-ми битному байту
CurPos:Byte;    //текущая позиция в массиве TBase64.ByteArr обрабатываемого
                 //8-ми битного байта-приемника
Begin {DecodeBase64}
//обнуляем значния всех переменных
CurPos:=0;
Dest:=0;
NextNum:=1;
FillChar(Result,SizeOf(Result),#0);
//будем обрабатывать каждый из 4 символов base64-кодированной строки
For N:=1 To 4 Do
Begin {For N}
//будем обрабатывать каждый бит 6-ти битного числа-источника
For M:=0 To 5 Do
Begin {For M}
//если обрабатывается символ "отсутствие байтов", обнуляем число-приемник
If StringValue[N]='=' Then
Sour:=0
Else
//иначе в число источник записываем код символа
Sour:=Pos(StringValue[N],base64ABC)-1;
//делаем побитный сдвиг влево для чисел источник и премник
Sour:=Sour SHL M;
Dest:=Dest SHL 1;
//смотрим старший (шестой) бит 6-ти битного числа-источника
//если бит установлен, то устанавливаем меньший бит числа-преимника
If (Sour And 32)=32 Then
Dest:=Dest Or 1;
//увеличиваем счетчик побитной обработки 8-ми битного числа
Inc(NextNum);
//если обработаны все восемь бит
If NextNum > 8 Then
Begin {If NextNum}
//обнуляем флаг-счетчик
NextNum:=1;
//записываем в массив полученный байт
Result.ByteArr[CurPos]:=Dest;
//если обрабатывался символ "знак отсутствия байта"
If StringValue[N]='=' Then
//обнулим полученный байт
Result.ByteArr[CurPos]:=0
Else
//иначе, увеличим счетчик считанных байтов
Result.ByteCount:=CurPos+1;
//будем обрабатывать следующий байт в массиве байтов TBase64.ByteArr
Inc(CurPos);
Dest:=0;
End;   {If NextNum}
End;   {For M}
End;   {For N}
End;  {DecodeBase64}
//================================DecodeBase64==================================
//******************************************************************************
//===============================StrToStrBase64=================================
Function StrToStrBase64(Value:String):String;
Var
Base64:TBase64;
TempStr:String;
Begin {StrToStrBase64}
Result:='';
While Length(Value)>0 Do
Begin
FillChar(Base64,SizeOf(Base64),#0);
TempStr:=Copy(Value,1,3);
Base64.ByteCount:=Length(TempStr);
Move(TempStr[1],Base64.ByteArr,Length(TempStr));

(*
Base64.ByteArr[0]:=Ord(TempStr[1]);
Base64.ByteArr[1]:=Ord(TempStr[2]);
Base64.ByteArr[2]:=Ord(TempStr[3]);
Base64.ByteCount:=Length(TempStr);
*)
Result:=Result+CodeBase64(Base64);
Delete(Value,1,3);
End;
End;  {StrToStrBase64}
//===============================StrToStrBase64=================================
end.
