Code: Select all
;
; Base16
;
; RFC 3548 / RFC 4648
;
; https://www.purebasic.fr/english/viewtopic.php?t=84910
;
CompilerIf #PB_Compiler_IsMainFile
EnableExplicit
CompilerEndIf
DataSection
Base16EncoderTable:
Data.a '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
Base16DecoderTable:
Data.b 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15
EndDataSection
Procedure.i Base16EncoderBuffer(*Input, InputSize.i, *Output, OutputSize.i, Flags.i=0)
Protected *InputAscii.Ascii, *InputEnd, *OutputAscii.Ascii, *TableAscii.Ascii
If OutputSize >= InputSize * 2
*InputAscii = *Input
*InputEnd = *Input + InputSize
*OutputAscii = *Output
While *InputAscii <> *InputEnd
*TableAscii = ?Base16EncoderTable + *InputAscii\a >> 4
*OutputAscii\a = *TableAscii\a
*OutputAscii + 1
*TableAscii = ?Base16EncoderTable + *InputAscii\a & %1111
*OutputAscii\a = *TableAscii\a
*OutputAscii + 1
*InputAscii + 1
Wend
EndIf
ProcedureReturn *OutputAscii - *Output
EndProcedure
Procedure.s Base16Encoder(*Input, InputSize.i, Flags.i=0)
Protected Base16$, *OutBuffer, Length.i
*OutBuffer = AllocateMemory(InputSize * Int(Round(8 / 5, #PB_Round_Up)))
If *OutBuffer
Length = Base16EncoderBuffer(*Input, InputSize, *OutBuffer, MemorySize(*OutBuffer), Flags)
If Length > 0
Base16$ = PeekS(*OutBuffer, Length, #PB_Ascii)
EndIf
FreeMemory(*OutBuffer)
EndIf
ProcedureReturn Base16$
EndProcedure
Procedure.i Base16DecoderBuffer(*Input, InputSize.i, *Output, OutputSize.i)
Protected *InputAscii.Ascii, *InputEnd, *OutputAscii.Ascii, *TableAscii.Ascii
*InputAscii = *Input
*InputEnd = *Input + InputSize
*OutputAscii = *Output
If OutputSize >= InputSize / 2
While *InputAscii <> *InputEnd
*TableAscii = ?Base16DecoderTable + (*InputAscii\a - '0')
*OutputAscii\a = *TableAscii\a << 4
*InputAscii + 1
*TableAscii = ?Base16DecoderTable + (*InputAscii\a - '0')
*OutputAscii\a | *TableAscii\a
*InputAscii + 1
*OutputAscii + 1
Wend
EndIf
ProcedureReturn *OutputAscii - *Output
EndProcedure
Procedure.i Base16Decoder(Input$, *Output, OutputSize.i)
Protected Length.i, *Input
*Input = Ascii(Input$)
If *Input
Length = Base16DecoderBuffer(*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$ = Base16Encoder(*Example, MemorySize(*Example) - 1)
Debug Encoded$
*Decoded = AllocateMemory(1024)
*Encoded = AllocateMemory(1024)
Length = Base16EncoderBuffer(*Example, MemorySize(*Example) - 1, *Encoded, MemorySize(*Encoded))
Debug PeekS(*Encoded, Length, #PB_Ascii)
Length = Base16DecoderBuffer(*Encoded, Length, *Decoded, MemorySize(*Decoded))
Debug PeekS(*Decoded, Length, #PB_UTF8|#PB_ByteLength)
;Debug PeekS(*Decoded, Length / 2)
FillMemory(*Decoded, MemorySize(*Decoded))
Length = Base16Decoder(Encoded$, *Decoded, MemorySize(*Decoded))
Debug PeekS(*Decoded, Length, #PB_UTF8|#PB_ByteLength)
CompilerEndIf