123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377 |
- {
- This file is part of the Free Pascal run time library.
- Copyright (c) 2021 by Michael Van Canneyt,
- member of the Free Pascal development team
- Base16,Base32,Base32-hex,Base32-crockford, Base64,Base64url encoding/decoding, with or without padding
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
- This program 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.
- **********************************************************************}
- {$IFNDEF FPC_DOTTEDUNITS}
- unit basenenc;
- {$ENDIF FPC_DOTTEDUNITS}
- {$mode ObjFPC}{$H+}
- interface
- {$IFDEF FPC_DOTTEDUNITS}
- uses System.SysUtils;
- {$ELSE FPC_DOTTEDUNITS}
- uses SysUtils;
- {$ENDIF FPC_DOTTEDUNITS}
- Type
- { TAlphabetEncoder }
- TReverseAlphabet = Array[0..255] of Byte;
- TStandardEncoder = (seBase16,
- seBase32,seBase32hex,seBase32CrockFord,
- seBase64,seBase64URL);
- TAlphabetEncoder = Class (TObject)
- protected
- Const
- StdBits : Array[TStandardEncoder] of Byte = (4,5,5,5,6,6);
- StdPads : Array[TStandardEncoder] of Byte = (0,8,8,8,4,4);
- StdAlpha : Array[TStandardEncoder] of String = (
- '0123456789ABCDEF',
- 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567',
- '0123456789ABCDEFGHIJKLMNOPQRSTUV',
- '0123456789ABCDEFGHJKMNPQRSTVWXYZ',
- 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
- 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_');
- Private
- FBits : Byte;
- FAlphabet : TBytes;
- FReverse : TReverseAlphabet;
- FPadding : Integer;
- class var StdEncoders : Array[TStandardEncoder] of TAlphabetEncoder;
- class function GetStdEncoder(AIndex: Integer): TAlphabetEncoder; static;
- public
- // Construct an encoder with alphabet, bits per letter, padding size in bits
- Constructor Create(Const aAlphabet : AnsiString; aBits : Byte; aPadding : Integer); virtual;
- // Destroy all standard encoders
- Class Destructor Done;
- // Create a standard encoder. You must free the result
- Class Function CreateStdEncoder(Std: TStandardEncoder): TAlphabetEncoder;
- // Encode data in buffer aBuffer with length aLen. If doPad is true, add padding if needed.
- Function Encode(aBuffer : PByte; aLen : Cardinal; doPad : Boolean = True) : AnsiString; virtual; overload;
- // Encode data in buffer aBuffer. If doPad is true, add padding if needed.
- Function Encode(aBuffer : TBytes; doPad : Boolean = True) : AnsiString; overload;
- // Encode data in string aBuffer. If doPad is true, add padding if needed.
- Function Encode(const aBuffer : AnsiString; doPad : Boolean = True) : AnsiString; overload;
- // Decode aSrcBuffer with length aLen.
- // Buffer must have enough room. Calculate maximum needed room with GetDecodeLen
- Function Decode(const aSrcBuffer : PByte; aLen : Integer; ABuffer : PByte; SkipWhiteSpace : Boolean = True) : Integer; virtual; overload;
- // Buffer must have enough room. Calculate maximum needed room with GetDecodeLen
- Function Decode(const S : AnsiString; ABuffer : PByte; SkipWhiteSpace : Boolean = True) : Integer; overload;
- // Return a buffer with decoded data.
- Function Decode(const S : AnsiString; SkipWhiteSpace : Boolean = True) : TBytes; overload;
- // Return a buffer with decoded data, starting with buffer.
- Function Decode(const aBuffer: PByte; aLen : Integer) : TBytes; overload;
- // Get a decoding length for the encoded string S. May be oversized due to padding.
- Function GetDecodeLen(const S : AnsiString) : Integer;
- // Bits per characters
- Property Bits : Byte Read FBits;
- // ASCII value of characters
- Property Alphabet : TBytes Read FAlphabet;
- // Reverse byte->character map
- Property Reverse : TReverseAlphabet Read FReverse;
- // Bits of padding
- Property Padding : Integer Read FPadding;
- // Standard encoders.
- Class Property Base16 : TAlphabetEncoder Index Ord(seBase16) Read GetStdEncoder;
- Class Property Base32 : TAlphabetEncoder Index Ord(seBase32) Read GetStdEncoder;
- Class Property Base32Hex : TAlphabetEncoder Index Ord(seBase32Hex) Read GetStdEncoder;
- Class Property Base32Crockford : TAlphabetEncoder Index Ord(seBase32Crockford) Read GetStdEncoder;
- Class Property Base64 : TAlphabetEncoder Index Ord(seBase64) Read GetStdEncoder;
- Class Property Base64URL : TAlphabetEncoder Index Ord(seBase64Url) Read GetStdEncoder;
- end;
- // Shortcut access to standard encoders.
- // Do not free the results !
- Function Base16 : TAlphabetEncoder;
- Function Base32 : TAlphabetEncoder;
- Function Base32Hex : TAlphabetEncoder;
- Function Base32Crockford : TAlphabetEncoder;
- Function Base64 : TAlphabetEncoder;
- Function Base64URL : TAlphabetEncoder;
- Function GetStandardEncoder(aEncoder : TStandardEncoder): TAlphabetEncoder;
- Function GetRawStringBytes(const S : AnsiString) : TBytes;
- Function GetRawStringFromBytes(B : TBytes) : RawByteString;
- implementation
- Function GetRawStringFromBytes(B : TBytes) : RawByteString;
- Var
- L : Integer;
- begin
- Result:='';
- L:=Length(B);
- SetLength(Result,L);
- If L>0 then
- Move(B[0],Result[1],L);
- end;
- Function GetRawStringBytes(Const S : AnsiString) : TBytes;
- Var
- L : Integer;
- begin
- Result:=[];
- L:=Length(S);
- SetLength(Result,L);
- If L>0 then
- Move(S[1],Result[0],L);
- end;
- Function TAlphabetEncoder.Encode(aBuffer : TBytes; doPad : Boolean = True) : AnsiString;
- begin
- Result:=Encode(PByte(aBuffer),Length(aBuffer),DoPad);
- end;
- function TAlphabetEncoder.Encode(Const aBuffer: AnsiString; doPad : Boolean = True): AnsiString;
- begin
- Result:=Encode(GetRawStringBytes(aBuffer),DoPad);
- end;
- Constructor TAlphabetEncoder.Create(const aAlphabet: AnsiString; aBits: Byte; aPadding: Integer);
- Var
- I : Integer;
- begin
- if (Length(aAlphabet)<2) or (Length(aAlphabet)>255) then
- Raise Exception.Create('Invalid alphabet length');
- FBits:=ABits;
- FPadding:=aPadding;
- SetLength(FAlphaBet,Length(aAlphabet));
- Move(aAlphabet[1],FAlphaBet[0],Length(aAlphabet));
- for I:=1 to Length(aAlphabet) do
- FReverse[Ord(aAlphaBet[i])]:=I;
- end;
- class destructor TAlphabetEncoder.Done;
- Var
- Std : TStandardEncoder;
- begin
- For Std in TStandardEncoder do
- FreeAndNil(StdEncoders[Std]);
- end;
- class function TAlphabetEncoder.CreateStdEncoder(Std : TStandardEncoder) : TAlphabetEncoder;
- begin
- Result:=TAlphaBetEncoder.Create(StdAlpha[Std],StdBits[Std],StdPads[Std]);
- end;
- class function TAlphabetEncoder.GetStdEncoder(AIndex: Integer): TAlphabetEncoder; static;
- Var
- Std : TStandardEncoder;
- begin
- Std:=TStandardEncoder(aIndex);
- if (StdEncoders[Std]=Nil) then
- StdEncoders[Std]:=CreateStdEncoder(Std);
- Result:=StdEncoders[Std];
- end;
- function TAlphabetEncoder.Encode(aBuffer: PByte; Alen : Cardinal; doPad : Boolean = True): Ansistring;
- var
- pSrc, pDest: pByte;
- I, Reg, lBits, PadLen,OutLen: integer;
- begin
- Result:='';
- Reg:=0;
- lBits:=0;
- PadLen:=0;
- OutLen:=aLen*8;
- OutLen:=(OutLen div Bits)+Ord((OutLen mod Bits) > 0 );
- if DoPad and (Padding>0) then
- begin
- PadLen:=OutLen mod Padding;
- if PadLen>0 then
- Inc(OutLen,(Padding-PadLen));
- end;
- SetLength(Result,OutLen);
- pSrc:=aBuffer;
- pDest:=@Result[1];
- for i:=1 to aLen do
- begin
- Reg:=Reg shl 8;
- Reg:=Reg or pSrc^;
- Inc(lBits,8);
- inc(pSrc);
- while (lBits>=Bits) do
- begin
- Dec(lBits,Bits);
- pDest^:=Alphabet[(Reg shr lBits)];
- Reg:= Reg-((Reg shr lBits) shl lBits);
- inc(pDest);
- end;
- end;
- if (lBits>0) then
- begin
- pDest^:=Alphabet[Reg shl (Bits-lBits)];
- inc(pDest);
- end;
- if DoPad and (PadLen>0) then
- FillChar(pDest^,Padding-PadLen,'=');
- end;
- Function TAlphabetEncoder.Decode(const aSrcBuffer : PByte; aLen : Integer; ABuffer : PByte;SkipWhiteSpace : Boolean = True) : Integer;
- Const
- WhiteSpace = [Ord(' '),10,13,9];
- var
- i, Reg, lBits : Integer;
- pSrc, pDest: pByte;
- begin
- Reg:=0;
- lBits:=0;
- Result:=0;
- while (aLen>0) and (aSrcBuffer[aLen-1]=Ord('=')) do
- Dec(aLen);
- if Alen=0 then exit;
- pSrc:=@aSrcBuffer[0];
- pDest:=aBuffer;
- I:=1;
- While (i<=aLen) do
- begin
- if SkipWhiteSpace then
- begin
- While (PSrc^ in WhiteSpace) and (I<=aLen) do
- begin
- Inc(PSrc);
- Inc(I);
- end;
- if I>aLen then
- break;
- end;
- if Reverse[pSrc^] <= 0 then
- break;
- Reg:=Reg shl Bits;
- Reg:=Reg or (Reverse[pSrc^]-1);
- Inc(lBits,Bits);
- while (lBits>=8) do
- begin
- Dec(lBits,8);
- pDest^:=byte(Reg shr lBits);
- inc(pDest);
- end;
- inc(pSrc);
- Inc(i);
- end;
- Result:=pDest-aBuffer;
- end;
- Function TAlphabetEncoder.GetDecodeLen(const S : AnsiString) : Integer;
- begin
- Result:=(length(s)*Bits) div 8;
- end;
- function TAlphabetEncoder.Decode(const S: AnsiString; SkipWhiteSpace : Boolean = True): TBytes;
- begin
- Result:=[];
- SetLength(Result,GetDecodeLen(S));
- SetLength(Result,Decode(S,PByte(Result),SkipWhiteSpace));
- end;
- function TAlphabetEncoder.Decode(const aBuffer: PByte; aLen: Integer): TBytes;
- begin
- Result:=[];
- SetLength(Result,(aLen*Bits) div 8);
- SetLength(Result,Decode(aBuffer,aLen,PByte(Result)));
- end;
- Function TAlphabetEncoder.Decode(const S : AnsiString; ABuffer : PByte;SkipWhiteSpace : Boolean = True) : Integer; overload;
- begin
- Result:=Decode(PByte(S),Length(S),ABuffer,SkipWhiteSpace);
- end;
- Function Base16 : TAlphabetEncoder;
- begin
- Result:=TAlphabetEncoder.Base16;
- end;
- Function Base32 : TAlphabetEncoder;
- begin
- Result:=TAlphabetEncoder.Base32;
- end;
- Function Base32Hex : TAlphabetEncoder;
- begin
- Result:=TAlphabetEncoder.Base32Hex;
- end;
- Function Base32CrockFord : TAlphabetEncoder;
- begin
- Result:=TAlphabetEncoder.Base32CrockFord;
- end;
- Function Base64 : TAlphabetEncoder;
- begin
- Result:=TAlphabetEncoder.Base64;
- end;
- Function Base64URL : TAlphabetEncoder;
- begin
- Result:=TAlphabetEncoder.Base64URL;
- end;
- Function GetStandardEncoder(aEncoder : TStandardEncoder): TAlphabetEncoder;
- begin
- Result:=TAlphabetEncoder.GetStdEncoder(Ord(aEncoder));
- end;
- end.
|