248 lines
6.7 KiB
ObjectPascal
248 lines
6.7 KiB
ObjectPascal
|
{*******************************************************}
|
||
|
|
||
|
{ Renegade BBS }
|
||
|
|
||
|
{ Copyright (c) 1990-2013 The Renegade Dev Team }
|
||
|
{ Copyleft (ↄ) 2016-2017 Renegade BBS }
|
||
|
|
||
|
{ This file is part of Renegade BBS }
|
||
|
|
||
|
{ Renegade is free software: you can redistribute it }
|
||
|
{ and/or modify it under the terms of the GNU General }
|
||
|
{ Public License as published by the Free Software }
|
||
|
{ Foundation, either version 3 of the License, or }
|
||
|
{ (at your option) any later version. }
|
||
|
|
||
|
{ Renegade is distributed in the hope that it will be }
|
||
|
{ useful, but WITHOUT ANY WARRANTY; without even the }
|
||
|
{ implied warranty of MERCHANTABILITY or FITNESS FOR }
|
||
|
{ A PARTICULAR PURPOSE. See the GNU General Public }
|
||
|
{ License for more details. }
|
||
|
|
||
|
{ You should have received a copy of the GNU General }
|
||
|
{ Public License along with Renegade. If not, see }
|
||
|
{ <http://www.gnu.org/licenses/>. }
|
||
|
|
||
|
{*******************************************************}
|
||
|
{ _______ __ }
|
||
|
{ | _ .-----.-----.-----.-----.---.-.--| .-----. }
|
||
|
{ |. l | -__| | -__| _ | _ | _ | -__| }
|
||
|
{ |. _ |_____|__|__|_____|___ |___._|_____|_____| }
|
||
|
{ |: | | |_____| }
|
||
|
{ |::.|:. | }
|
||
|
{ `--- ---' }
|
||
|
{*******************************************************}
|
||
|
|
||
|
unit Hash.Base64;
|
||
|
|
||
|
{$codepage utf8}
|
||
|
{$h+}{$mode objfpc}
|
||
|
interface
|
||
|
|
||
|
uses
|
||
|
Classes,
|
||
|
SysUtils,
|
||
|
Base64;
|
||
|
|
||
|
const
|
||
|
BSDEncodeTable: array[0..63] of char =
|
||
|
{ 0:} './' +
|
||
|
{ 2:} 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' +
|
||
|
{28:} 'abcdefghijklmnopqrstuvwxyz' +
|
||
|
{54:} '0123456789';
|
||
|
|
||
|
BSDDecodeTable: array[#0..#127] of integer = (
|
||
|
{ 0:} -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||
|
{ 16:} -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||
|
{ 32:} -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1,
|
||
|
{ 48:} 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, -1, -1, -1, -1, -1, -1,
|
||
|
{ 64:} -1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
|
||
|
{ 80:} 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, -1, -1, -1, -1, -1,
|
||
|
{ 96:} -1, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
|
||
|
{113:} 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, -1, -1, -1, -1, -1
|
||
|
);
|
||
|
|
||
|
type
|
||
|
RTBase64 = object
|
||
|
private
|
||
|
function Char64(Character: AnsiChar): SizeInt;
|
||
|
procedure AppendChar(var WorkingResult: TBytes; Value: byte);
|
||
|
public
|
||
|
function Encode(S: UTF8String): ansistring; static;
|
||
|
function Decode(S: ansistring): UTF8String; static;
|
||
|
function BSDEncode(S: UTF8STring): ansistring; static;
|
||
|
function BSDDecode(S: ansistring): UTF8STring; static;
|
||
|
function BSDEncodeBytes(const RawByteData: TBytes;
|
||
|
CharacterLength: Sizeint): ansistring;
|
||
|
function BSDDecodeBytes(const EncodedString: ansistring): TBytes;
|
||
|
end;
|
||
|
|
||
|
implementation
|
||
|
|
||
|
function RTBase64.Char64(Character: AnsiChar): SizeInt;
|
||
|
begin
|
||
|
if Ord(Character) > Length(BSDDecodeTable) then
|
||
|
begin
|
||
|
Result := -1;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
Result := BSDDecodeTable[Character];
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure RTBase64.AppendChar(var WorkingResult: TBytes; Value: byte);
|
||
|
var
|
||
|
i: SizeUint;
|
||
|
begin
|
||
|
i := Length(WorkingResult);
|
||
|
SetLength(WorkingResult, i + 1);
|
||
|
WorkingResult[i] := Value;
|
||
|
end;
|
||
|
|
||
|
|
||
|
function RTBase64.Encode(S: UTF8String): ansistring;
|
||
|
begin
|
||
|
Result := EncodeStringBase64(S);
|
||
|
end;
|
||
|
|
||
|
function RTBase64.Decode(S: ansistring): UTF8String;
|
||
|
begin
|
||
|
Result := DecodeStringBase64(S);
|
||
|
end;
|
||
|
|
||
|
function RTBase64.BSDEncode(S: UTF8String): ansistring;
|
||
|
var
|
||
|
TBaseBytes: TBytes;
|
||
|
begin
|
||
|
|
||
|
SetLength(TBaseBytes, Length(S) + 1);
|
||
|
Move(S[1], TBaseBytes[0], Length(S) + 1);
|
||
|
Result := RTBase64.BSDEncodeBytes(TBaseBytes, Length(TBaseBytes));
|
||
|
end;
|
||
|
|
||
|
function RTBase64.BSDDecode(S: ansistring): UTF8String;
|
||
|
var
|
||
|
TBaseBytes: TBytes;
|
||
|
begin
|
||
|
SetLength(TBaseBytes, Length(S) + 1);
|
||
|
|
||
|
TBaseBytes := RTBase64.BSDDecodeBytes(S);
|
||
|
SetLength(Result, Length(TBaseBytes));
|
||
|
Move(TBaseBytes[0], Result[1], Length(TBaseBytes));
|
||
|
end;
|
||
|
|
||
|
function RTBase64.BSDEncodeBytes(const RawByteData: TBytes;
|
||
|
CharacterLength: Sizeint): ansistring;
|
||
|
var
|
||
|
i, b1, b2: SizeInt;
|
||
|
begin
|
||
|
Result := '';
|
||
|
if (CharacterLength <= 0) or (CharacterLength > Length(RawByteData)) then
|
||
|
begin
|
||
|
Exit;
|
||
|
end;
|
||
|
|
||
|
i := 0;
|
||
|
while i < CharacterLength do
|
||
|
begin
|
||
|
b1 := RawByteData[i] and $ff;
|
||
|
Inc(i);
|
||
|
|
||
|
Result := Result + BSDEncodeTable[(b1 shr 2) and $3f];
|
||
|
b1 := (b1 and $03) shl 4;
|
||
|
if i >= CharacterLength then
|
||
|
begin
|
||
|
Result := Result + BSDEncodeTable[b1 and $3f];
|
||
|
Exit;
|
||
|
end;
|
||
|
|
||
|
b2 := RawByteData[i] and $ff;
|
||
|
Inc(i);
|
||
|
b1 := b1 or ((b2 shr 4) and $0f);
|
||
|
|
||
|
Result := Result + BSDEncodeTable[b1 and $3f];
|
||
|
b1 := (b2 and $0f) shl 2;
|
||
|
if i >= CharacterLength then
|
||
|
begin
|
||
|
Result := Result + BSDEncodeTable[b1 and $3f];
|
||
|
Exit;
|
||
|
end;
|
||
|
|
||
|
b2 := RawByteData[i] and $ff;
|
||
|
Inc(i);
|
||
|
b1 := b1 or ((b2 shr 6) and $03);
|
||
|
Result := Result + BSDEncodeTable[b1 and $3f];
|
||
|
Result := Result + BSDEncodeTable[b2 and $3f];
|
||
|
end;
|
||
|
|
||
|
end;
|
||
|
|
||
|
function RTBase64.BSDDecodeBytes(const EncodedString: ansistring): TBytes;
|
||
|
var
|
||
|
i, EncodedStringLength, c1, c2, c3, c4: Sizeint;
|
||
|
|
||
|
begin
|
||
|
SetLength(Result, 0);
|
||
|
i := 1;
|
||
|
EncodedStringLength := Length(EncodedString);
|
||
|
while (i < EncodedStringLength) and (Length(Result) < EncodedStringLength) do
|
||
|
begin
|
||
|
c1 := self.Char64(EncodedString[i]);
|
||
|
Inc(i);
|
||
|
c2 := self.Char64(EncodedString[i]);
|
||
|
Inc(i);
|
||
|
if (c1 = -1) or (c2 = -1) then
|
||
|
begin
|
||
|
Exit;
|
||
|
end;
|
||
|
|
||
|
{
|
||
|
Now we have at least one byte in c1|c2
|
||
|
c1 = ..111111
|
||
|
c2 = ..112222
|
||
|
}
|
||
|
self.AppendChar(Result, (c1 shl 2) or ((c2 and $30) shr 4));
|
||
|
//If there's a 3rd character, then we can use c2|c3 to form the second byte
|
||
|
if (i > EncodedStringLength) or (Length(Result) >= EncodedStringLength) then
|
||
|
begin
|
||
|
Break;
|
||
|
end;
|
||
|
|
||
|
c3 := self.Char64(EncodedString[i]);
|
||
|
Inc(i);
|
||
|
if (c3 = -1) then
|
||
|
begin
|
||
|
Exit;
|
||
|
end;
|
||
|
|
||
|
{
|
||
|
Now we have the next byte in c2|c3
|
||
|
c2 = ..112222
|
||
|
c3 = ..222233
|
||
|
}
|
||
|
self.AppendChar(Result, ((c2 and $0f) shl 4) or ((c3 and $3c) shr 2));
|
||
|
//If there's a 4th caracter, then we can use c3|c4 to form the third byte
|
||
|
if (i > EncodedStringLength) or (Length(Result) >= EncodedStringLength) then
|
||
|
begin
|
||
|
Break;
|
||
|
end;
|
||
|
|
||
|
c4 := self.Char64(EncodedString[i]);
|
||
|
Inc(i);
|
||
|
if c4 = -1 then
|
||
|
begin
|
||
|
Exit;
|
||
|
end;
|
||
|
|
||
|
{
|
||
|
Now we have the next byte in c3|c4
|
||
|
c3 = ..222233
|
||
|
c4 = ..333333
|
||
|
}
|
||
|
self.AppendChar(Result, ((c3 and $03) shl 6) or c4);
|
||
|
end; { While }
|
||
|
end;
|
||
|
|
||
|
end.
|