program Base36Codec;
{$mode objfpc}{$H+}{$J-}
{
Base‑36 encoding/decoding in Free Pascal
--------------------------------------------------
Base‑36 digits: 0–9, A–Z
Encoding:
- Convert string → big integer (base‑256)
- Convert big integer → base‑36
Decoding:
- Convert base‑36 → big integer
- Convert big integer → original bytes
We store the big integer as an array of 32‑bit chunks (little‑endian).
}
uses
SysUtils;
const
Base36Digits: string = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
{ Convert Base‑36 character → numeric value }
function Base36Value(c: Char): Integer;
begin
if (c >= '0') and (c <= '9') then
Result := Ord(c) - Ord('0')
else
Result := Ord(c) - Ord('A') + 10;
end;
{
EncodeToBase36:
---------------
Converts a Pascal string into Base‑36 text.
Uses manual big‑integer arithmetic:
number[i] holds a 32‑bit chunk of the integer.
}
function EncodeToBase36(const input: string): string;
var
number: array of Cardinal;
nsize: Integer;
i, j: Integer;
carry: Cardinal;
value: QWord;
remainder: Cardinal;
encoded: string;
c: Char;
begin
SetLength(number, Length(input) + 4);
number[0] := 0;
nsize := 1;
{ Step 1: Convert string → big integer (base‑256) }
for i := 1 to Length(input) do
begin
carry := Ord(input[i]);
for j := 0 to nsize - 1 do
begin
value := QWord(number[j]) * 256 + carry;
number[j] := Cardinal(value and $FFFFFFFF);
carry := Cardinal(value shr 32);
end;
if carry > 0 then
begin
number[nsize] := carry;
Inc(nsize);
end;
end;
{ Step 2: Convert big integer → Base‑36 }
encoded := '';
while not ((nsize = 1) and (number[0] = 0)) do
begin
remainder := 0;
for j := nsize - 1 downto 0 do
begin
value := (QWord(remainder) shl 32) or number[j];
number[j] := Cardinal(value div 36);
remainder := Cardinal(value mod 36);
end;
while (nsize > 1) and (number[nsize - 1] = 0) do
Dec(nsize);
encoded := encoded + Base36Digits[remainder + 1];
end;
{ Reverse the Base‑36 output }
for i := 1 to Length(encoded) div 2 do
begin
c := encoded[i];
encoded[i] := encoded[Length(encoded) - i + 1];
encoded[Length(encoded) - i + 1] := c;
end;
Result := encoded;
end;
{
DecodeFromBase36:
-----------------
Converts Base‑36 text back into the original string.
Steps:
1. Convert Base‑36 → big integer
2. Convert big integer → bytes (base‑256)
}
function DecodeFromBase36(const encoded: string): string;
var
number: array of Cardinal;
nsize: Integer;
i, j: Integer;
digit: Integer;
carry: Cardinal;
value: QWord;
remainder: Cardinal;
output: string;
c: Char;
begin
SetLength(number, Length(encoded) + 4);
number[0] := 0;
nsize := 1;
{ Step 1: Base‑36 → big integer }
for i := 1 to Length(encoded) do
begin
digit := Base36Value(encoded[i]);
carry := digit;
for j := 0 to nsize - 1 do
begin
value := QWord(number[j]) * 36 + carry;
number[j] := Cardinal(value and $FFFFFFFF);
carry := Cardinal(value shr 32);
end;
if carry > 0 then
begin
number[nsize] := carry;
Inc(nsize);
end;
end;
{ Step 2: big integer → original bytes }
output := '';
while not ((nsize = 1) and (number[0] = 0)) do
begin
remainder := 0;
for j := nsize - 1 downto 0 do
begin
value := (QWord(remainder) shl 32) or number[j];
number[j] := Cardinal(value div 256);
remainder := Cardinal(value mod 256);
end;
while (nsize > 1) and (number[nsize - 1] = 0) do
Dec(nsize);
output := output + Chr(remainder);
end;
{ Reverse the output bytes }
for i := 1 to Length(output) div 2 do
begin
c := output[i];
output[i] := output[Length(output) - i + 1];
output[Length(output) - i + 1] := c;
end;
Result := output;
end;
{ Main program }
var
text, encoded, decoded: string;
begin
text := 'Hello Universe!';
encoded := EncodeToBase36(text);
decoded := DecodeFromBase36(encoded);
WriteLn('Original: ', text);
WriteLn('Base-36 encoded: ', encoded);
WriteLn('Decoded: ', decoded);
end.
(*
run:
Original: Hello Universe!
Base-36 encoded: LP4N024HJ1YVBVD84Y8TYQP
Decoded: Hello Universe!
*)