Codificar y descodificar un String en Base 64
En una de mis aplicaciones, utilicé el siguiente código adaptado por Jacob Dybala (el código original es de David Barton) donde se nos muestra un algoritmo simple de codificación y descodificación de un string en base64. Éste ejemplo funcionó muy bien para codificar una serie de passwords y luego almancenarlos en una BD. Podemos variar el algoritmo a nuestro gusto por si queremos añadir un charset diferente o mejorar alguna cosa de su implementación. Aunque en la entrada de Jacob Dybala, él mejora y optimiza bastante el tema del espacio utilizado. Para éste ejemplo desarrollé una pequeña aplicación llamada Thundax Encode/Decode String Base64, y la podréis descargar para comprobar si os gusta la salida del algoritmo. También podréis encontrar varios codificadores base64 online, aquí os dejo varios enlaces para que los probéis:Código fuente:
unit String64;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
const
B64Table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
function Base64Decode(const S: string): string;
function Base64Encode(const S: string): string;
implementation
{$R *.dfm}
function Base64Encode(const S: string): string;
var
InBuf: array[0..2] of Byte;
OutBuf: array[0..3] of Char;
iI, iJ: Integer;
begin
SetLength(Result, ((Length(S) + 2) div 3) * 4);
for iI := 1 to ((Length(S) + 2) div 3) do
begin
if Length(S) < (iI * 3) then
Move(S[(iI - 1) * 3 + 1], InBuf, Length(S) - (iI - 1) * 3)
else
Move(S[(iI - 1) * 3 + 1], InBuf, 3);
OutBuf[0] := B64Table[((InBuf[0] and $FC) shr 2) + 1];
OutBuf[1] := B64Table[(((InBuf[0] and $3) shl 4) or ((InBuf[1] and $F0) shr 4)) + 1];
OutBuf[2] := B64Table[(((InBuf[1] and $F) shl 2) or ((InBuf[2] and $C0) shr 6)) + 1];
OutBuf[3] := B64Table[(InBuf[2] and $3F) + 1];
Move(OutBuf, Result[(iI - 1) * 4 + 1], 4);
end;
if Length(S) mod 3 = 1 then
begin
Result[Length(Result) - 1] := '=';
Result[Length(Result)] := '=';
end
else if Length(S) mod 3 = 2 then
Result[Length(Result)] := '=';
end;
function Base64Decode(const S: string): string;
var
OutBuf: array[0..2] of Byte;
InBuf: array[0..3] of Byte;
iI, iJ: Integer;
begin
if Length(S) mod 4 <> 0 then
raise Exception.Create('Base64: Incorrect string format');
SetLength(Result, ((Length(S) div 4) - 1) * 3);
for iI := 1 to (Length(S) div 4) - 1 do
begin
Move(S[(iI - 1) * 4 + 1], InBuf, 4);
for iJ := 0 to 3 do
case InBuf[iJ] of
43: InBuf[iJ] := 62;
48..57: Inc(InBuf[iJ], 4);
65..90: Dec(InBuf[iJ], 65);
97..122: Dec(InBuf[iJ], 71);
else
InBuf[iJ] := 63;
end;
OutBuf[0] := (InBuf[0] shl 2) or ((InBuf[1] shr 4) and $3);
OutBuf[1] := (InBuf[1] shl 4) or ((InBuf[2] shr 2) and $F);
OutBuf[2] := (InBuf[2] shl 6) or (InBuf[3] and $3F);
Move(OutBuf, Result[(iI - 1) * 3 + 1], 3);
end;
if Length(S) <> 0 then
begin
Move(S[Length(S) - 3], InBuf, 4);
if InBuf[2] = 61 then
begin
for iJ := 0 to 1 do
case InBuf[iJ] of
43: InBuf[iJ] := 62;
48..57: Inc(InBuf[iJ], 4);
65..90: Dec(InBuf[iJ], 65);
97..122: Dec(InBuf[iJ], 71);
else
InBuf[iJ] := 63;
end;
OutBuf[0] := (InBuf[0] shl 2) or ((InBuf[1] shr 4) and $3);
Result := Result + Char(OutBuf[0]);
end
else if InBuf[3] = 61 then
begin
for iJ := 0 to 2 do
case InBuf[iJ] of
43: InBuf[iJ] := 62;
48..57: Inc(InBuf[iJ], 4);
65..90: Dec(InBuf[iJ], 65);
97..122: Dec(InBuf[iJ], 71);
else
InBuf[iJ] := 63;
end;
OutBuf[0] := (InBuf[0] shl 2) or ((InBuf[1] shr 4) and $3);
OutBuf[1] := (InBuf[1] shl 4) or ((InBuf[2] shr 2) and $F);
Result := Result + Char(OutBuf[0]) + Char(OutBuf[1]);
end
else
begin
for iJ := 0 to 3 do
case InBuf[iJ] of
43: InBuf[iJ] := 62;
48..57: Inc(InBuf[iJ], 4);
65..90: Dec(InBuf[iJ], 65);
97..122: Dec(InBuf[iJ], 71);
else
InBuf[iJ] := 63;
end;
OutBuf[0] := (InBuf[0] shl 2) or ((InBuf[1] shr 4) and $3);
OutBuf[1] := (InBuf[1] shl 4) or ((InBuf[2] shr 2) and $F);
OutBuf[2] := (InBuf[2] shl 6) or (InBuf[3] and $3F);
Result := Result + Char(OutBuf[0]) + Char(OutBuf[1]) + Char(OutBuf[2]);
end;
end;
end;
procedure TForm3.Button1Click(Sender: TObject);
begin
if Edit1.text = '' then
exit;
Edit2.text := Base64Encode(Edit1.text);
end;
procedure TForm3.Button2Click(Sender: TObject);
begin
if Edit2.text = '' then
exit;
Edit1.text := Base64Decode(Edit2.text);
end;
end.
Aplicación:

Espero que os guste el algoritmo, ya que en mi opinión creo que hay que tenerlo siempre a mano.
- Enlaces de interés:
%20applied%20to%20Transformer%20models%20in%20machine%20learning.%20The%20image%20shows%20a%20neural%20networ.webp)

Hola Jordi, hace unos días que utilicé el código de ésta función (Base64Encode) para incorporarlo en una UDF que hice para Firebird, te agradezco este código. Te comento que me topé con un problema al ejecutarla ya que vi que era necesario iniciar a ceros el Inbuf antes de asignarle los datos de S, ya que si no lo hacía, el Inbuf se llevaba en la segunda y siguiente o en la tercera posición el byte del ciclo anterior y la cadena que regresaba era incorrecta en el último byte. Espero haberme explicado. Saludos y te vuelvo a dar las gracias por este magnífico pedazo de código.
ReplyDelete