Code: Select all
;
; Base32
;
; RFC 3548 / RFC 4648
;
; https://www.purebasic.fr/english/viewtopic.php?t=84906
;
CompilerIf #PB_Compiler_IsMainFile
EnableExplicit
CompilerEndIf
DataSection
Base32EncoderTable:
Data.a 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '2', '3', '4', '5', '6', '7'
Base32DecoderTable:
Data.b -1, -1, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 , 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25
EndDataSection
Procedure.i Base32EncoderBuffer(*Input, InputSize.i, *Output, OutputSize.i, Flags.i=0)
Protected Index.i, i.i, *OutputAscii.Ascii, *TableAscii.Ascii, c.i, n.i
Protected Dim Block.a(4)
*OutputAscii = *Output
While i < InputSize
If i + 5 < InputSize
CopyMemory(*Input + i, @Block(0), 5)
c = 8
Else
FillMemory(@Block(0), 5)
CopyMemory(*Input + i, @Block(0), InputSize - i)
Select 5 - (InputSize - i)
Case 1 : c = 7
Case 2 : c = 5
Case 3 : c = 4
Case 4 : c = 2
EndSelect
EndIf
n = 1
While n <= c
Select n
Case 1 : Index = Block(0) >> 3
Case 2 : Index = (Block(0) & %111) << 2 | Block(1) >> 6
Case 3 : Index = (Block(1) & %111110) >> 1
Case 4 : Index = (Block(1) & %1) << 4 | Block(2) >> 4
Case 5 : Index = (Block(2) & %1111) << 1 | Block(3) >> 7
Case 6 : Index = (Block(3) & %1111100) >> 2
Case 7 : Index = (Block(3) & %11) << 3 | Block(4) >> 5
Case 8 : Index = (Block(4) & %11111)
EndSelect
*TableAscii = ?Base32EncoderTable + Index
*OutputAscii\a = *TableAscii\a
*OutputAscii + 1
n + 1
Wend
i + 5
Wend
If (Flags & #PB_Cipher_NoPadding) = 0
For i = 7 To c Step -1
*OutputAscii\a = '='
*OutputAscii + 1
Next i
EndIf
ProcedureReturn *OutputAscii - *Output
EndProcedure
Procedure.s Base32Encoder(*Input, InputSize.i, Flags.i=0)
Protected Base32$, *OutBuffer, Length.i
*OutBuffer = AllocateMemory(InputSize * Int(Round(8 / 5, #PB_Round_Up)))
If *OutBuffer
Length = Base32EncoderBuffer(*Input, InputSize, *OutBuffer, MemorySize(*OutBuffer), Flags)
If Length > 0
Base32$ = PeekS(*OutBuffer, Length, #PB_Ascii)
EndIf
FreeMemory(*OutBuffer)
EndIf
ProcedureReturn Base32$
EndProcedure
Procedure.i Base32DecoderBuffer(*Input, InputSize.i, *Output, OutputSize.i)
Protected *InputAscii.Ascii, *OutputAscii.Ascii, i.i, Byte.a, *TableAscii.Ascii, n.i, c.i
Protected Dim Block.a(4)
*InputAscii = *Input
*OutputAscii = *Output
While i < InputSize
FillMemory(@Block(0), 4)
n = 1
While n <= 8
If *InputAscii\a = '='
Break
Else
*TableAscii = ?Base32DecoderTable + *InputAscii\a - '0'
;Debug Chr(*InputAscii\a) + " " + Str(*InputAscii\a - '0') + " " + Str(*TableAscii\a) + " 0x" + Hex(*TableAscii\a)
Select n
Case 1 : Block(0) = *TableAscii\a << 3
Case 2 : Block(0) | (*TableAscii\a >> 2) : c = 1 : Block(1) = (*TableAscii\a & %11) << 6
Case 3 : Block(1) | (*TableAscii\a << 1)
Case 4 : Block(1) | (*TableAscii\a >> 4) : c = 2 : Block(2) = (*TableAscii\a & %1111) << 4
Case 5 : Block(2) | (*TableAscii\a >> 1) : c = 3 : Block(3) = (*TableAscii\a & %1) << 7
Case 6 : Block(3) | (*TableAscii\a << 2)
Case 7 : Block(3) | (*TableAscii\a >> 3) : c = 4 : Block(4) = (*TableAscii\a & %111) << 5
Case 8 : Block(4) | *TableAscii\a : c = 5
EndSelect
*InputAscii + 1
EndIf
n + 1
Wend
CopyMemory(@Block(0), *OutputAscii, c)
*OutputAscii + c
i + 8
Wend
ProcedureReturn *OutputAscii - *Output
EndProcedure
Procedure.i Base32Decoder(Input$, *Output, OutputSize.i)
Protected Length.i, *Input
*Input = Ascii(Input$)
If *Input
Length = Base32DecoderBuffer(*Input, MemorySize(*Input) - 1, *Output, OutputSize)
FreeMemory(*Input)
EndIf
ProcedureReturn Length
EndProcedure
CompilerIf #PB_Compiler_IsMainFile
Define Example$, *Example, *Decoded, *Encoded, Length.i, Encoded$
Example$ = "This is a test string!"
*Example = UTF8(Example$)
;*Example = AllocateMemory(StringByteLength(Example$) + 2)
;PokeS(*Example, Example$)
Encoded$ = Base32Encoder(*Example, MemorySize(*Example) - 1)
Debug Encoded$
*Decoded = AllocateMemory(1024)
*Encoded = AllocateMemory(1024)
Length = Base32EncoderBuffer(*Example, MemorySize(*Example) - 1, *Encoded, MemorySize(*Encoded))
Debug PeekS(*Encoded, Length, #PB_Ascii)
Length = Base32DecoderBuffer(*Encoded, Length, *Decoded, MemorySize(*Decoded))
Debug PeekS(*Decoded, Length, #PB_UTF8|#PB_ByteLength)
;Debug PeekS(*Decoded, Length / 2)
FillMemory(*Decoded, MemorySize(*Decoded))
Length = Base32Decoder(Encoded$, *Decoded, MemorySize(*Decoded))
Debug PeekS(*Decoded, Length, #PB_UTF8|#PB_ByteLength)
CompilerEndIf
