Base64 Helper functions
Posted: Mon Jun 27, 2016 1:47 pm
Base64 has come up a lot lately.
It sounds like Fred is going to make it easier to use in a future version (functions will return strings, so no allocations / ASCII peeks are needed).
But in the meantime, here are some helper functions to simplify Base64 usage.
Base64EncodeMemory(*Input, InputSize[, Flags]) - takes a pointer to some data and returns a Base64-formatted string
Base64DecodeToMemory(Input) - takes a Base64 string and returns a decoded memory block
Also, if you are encoding/decoding strings, these functions will auto-convert to/from UTF-8 so that Base64 results are the same in ASCII or Unicode mode.
Base64EncodeString(Input[, Flags]) - returns a Base64-formatted string
Base64DecodeToString(Input) - takes a Base64 string and returns a decoded string
Apologies if similar functions have been posted many times before!
Notes:
o EnableExplicit safe
o ASCII/Unicode safe
o Multiple-IncludeFile safe
It sounds like Fred is going to make it easier to use in a future version (functions will return strings, so no allocations / ASCII peeks are needed).
But in the meantime, here are some helper functions to simplify Base64 usage.
Base64EncodeMemory(*Input, InputSize[, Flags]) - takes a pointer to some data and returns a Base64-formatted string
Base64DecodeToMemory(Input) - takes a Base64 string and returns a decoded memory block
Also, if you are encoding/decoding strings, these functions will auto-convert to/from UTF-8 so that Base64 results are the same in ASCII or Unicode mode.
Base64EncodeString(Input[, Flags]) - returns a Base64-formatted string
Base64DecodeToString(Input) - takes a Base64 string and returns a decoded string
Apologies if similar functions have been posted many times before!
Notes:
o EnableExplicit safe
o ASCII/Unicode safe
o Multiple-IncludeFile safe
Code: Select all
; +-------------------+
; | Base64_Helper.pbi |
; +-------------------+
; | 2016.06.24 . Creation (PureBasic 5.42)
; | .28 . Fixed encode buffer size to prevent overwrite in edge cases
; | .29 . Decoder now appends '=' padding, if missing
; | .30 . Added EncodeFile and DecodeToFile functions
CompilerIf (Not Defined(_Base64_Helper_Included, #PB_Constant))
#_Base64_Helper_Included = #True
CompilerIf (#PB_Compiler_IsMainFile)
EnableExplicit
CompilerEndIf
;-
;- Procedures
Procedure.s Base64EncodeMemory(*Input, InputSize.i, Flags.i = #Null)
Protected Result.s
If (*Input And (InputSize > 0))
Protected OutputSize.i = (InputSize + 2) * 1.34 + 1
If (OutputSize < 64)
OutputSize = 64
EndIf
Protected *Output = AllocateMemory(OutputSize)
If (*Output)
If (Base64Encoder(*Input, InputSize, *Output, OutputSize, Flags))
Result = PeekS(*Output, OutputSize, #PB_Ascii)
EndIf
FreeMemory(*Output)
EndIf
EndIf
ProcedureReturn (Result)
EndProcedure
Procedure.s Base64EncodeString(Input.s, Flags.i = #Null)
Protected Result.s
If (Input)
Protected InputSize = StringByteLength(Input, #PB_UTF8)
Protected *Input = AllocateMemory(InputSize + 1)
If (*Input)
PokeS(*Input, Input, -1, #PB_UTF8)
Result = Base64EncodeMemory(*Input, InputSize, Flags)
FreeMemory(*Input)
EndIf
EndIf
ProcedureReturn (Result)
EndProcedure
Procedure.s Base64EncodeFile(InputFile.s, Flags.i = #Null)
Protected Result.s
If (InputFile)
Protected FN.i = ReadFile(#PB_Any, InputFile)
If (FN)
Protected Remaining.i = Lof(FN)
If (Remaining > 0)
Protected BufferSize.i = 1500000 ; divisble by 3
Protected *Buffer = AllocateMemory(BufferSize)
If (*Buffer)
While (Remaining > 0)
Protected n.i = BufferSize
If (n > Remaining)
n = Remaining
EndIf
If (ReadData(FN, *Buffer, n) = n)
Result + Base64EncodeMemory(*Buffer, n, Flags)
Remaining - n
Else
Result = ""
Break
EndIf
Wend
FreeMemory(*Buffer)
EndIf
EndIf
CloseFile(FN)
EndIf
EndIf
ProcedureReturn (Result)
EndProcedure
Procedure.i Base64DecodeToMemory(Input.s)
Protected *Result
If (Input)
Select (Len(Input) % 4)
Case 2 : Input + "=="
Case 3 : Input + "="
EndSelect
Protected InputSize.i = StringByteLength(Input, #PB_Ascii)
Protected *Input = AllocateMemory(InputSize + 1)
If (*Input)
PokeS(*Input, Input, -1, #PB_Ascii)
Protected OutputSize.i = InputSize + 1
If (OutputSize < 64)
OutputSize = 64
EndIf
Protected *Output = AllocateMemory(OutputSize)
If (*Output)
If (Base64Decoder(*Input, InputSize, *Output, OutputSize))
CompilerIf (#True)
Input = RTrim(Input, "=")
Select (Len(Input) % 4)
Case 0
OutputSize = 3 * (Len(Input) / 4) + 0
Case 2
OutputSize = 3 * (Len(Input) / 4) + 1
Case 3
OutputSize = 3 * (Len(Input) / 4) + 2
EndSelect
*Output = ReAllocateMemory(*Output, OutputSize)
CompilerEndIf
*Result = *Output
Else
FreeMemory(*Output)
EndIf
EndIf
FreeMemory(*Input)
EndIf
EndIf
ProcedureReturn (*Result)
EndProcedure
Procedure.s Base64DecodeToString(Input.s)
Protected Result.s
Protected *Output = Base64DecodeToMemory(Input)
If (*Output)
Result = PeekS(*Output, MemorySize(*Output), #PB_UTF8 | #PB_ByteLength)
FreeMemory(*Output)
EndIf
ProcedureReturn (Result)
EndProcedure
Procedure.i Base64DecodeToFile(Input.s, OutputFile.s)
Protected Result.i
Protected *Output = Base64DecodeToMemory(Input)
If (*Output)
Protected FN.i = CreateFile(#PB_Any, OutputFile)
If (FN)
Result = WriteData(FN, *Output, MemorySize(*Output))
CloseFile(FN)
If (Result <= 0)
DeleteFile(OutputFile)
EndIf
EndIf
FreeMemory(*Output)
EndIf
ProcedureReturn (Result)
EndProcedure
;-
;- Demo Program
CompilerIf (#PB_Compiler_IsMainFile)
DisableExplicit
Debug Base64EncodeString("$")
Debug Base64DecodeToString(Base64EncodeString("$"))
Debug ""
Debug Base64EncodeString("Hello World!")
Debug Base64DecodeToString(Base64EncodeString("Hello World!"))
Debug ""
Debug Base64EncodeString("The quick brown fox jumps over the lazy dog.")
Debug Base64DecodeToString(Base64EncodeString("The quick brown fox jumps over the lazy dog."))
Debug ""
CompilerEndIf
CompilerEndIf
;-