Skip to content

Instantly share code, notes, and snippets.

@daily3014
Created December 10, 2025 20:52
Show Gist options
  • Select an option

  • Save daily3014/fc25ae3165387a3bccc2b530b04e3143 to your computer and use it in GitHub Desktop.

Select an option

Save daily3014/fc25ae3165387a3bccc2b530b04e3143 to your computer and use it in GitHub Desktop.
Ever wanted to encode a string in Base64? Can't be bothered with those bloated Text to Base64 websites? Too elegant for those overrated "terminals" or whatever? Now you can encode strings in Base64 straight in luau with TYPES!
--!strict
--!optimize 2
--!native
type function Base64(user_type)
if not user_type:is("singleton") then
error(`provided type is not a singleton: {user_type.tag}`)
end
local value = tostring(user_type:value() :: string)
local buff = buffer.fromstring(value)
local PADDING_CHARACTER = 61
local ALPHABET_INDEX = buffer.create(64) do
local Characters = {
65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,
113, 114, 115, 116, 117, 118, 119, 120, 121, 122,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
43, 47
}
for Index = 0, 63 do
buffer.writeu8(ALPHABET_INDEX, Index, Characters[Index + 1])
end
end
local DIRECT_LOOKUP = buffer.create(256) do
for Index = 0, 255 do
buffer.writeu8(DIRECT_LOOKUP, Index, buffer.readu8(ALPHABET_INDEX, bit32.band(Index, 63)))
end
end
local DECODE_TABLE = buffer.create(256) do
for Index = 0, 255 do
buffer.writeu8(DECODE_TABLE, Index, 255)
end
for Index = 65, 90 do
buffer.writeu8(DECODE_TABLE, Index, Index - 65)
end
for Index = 97, 122 do
buffer.writeu8(DECODE_TABLE, Index, Index - 97 + 26)
end
for Index = 48, 57 do
buffer.writeu8(DECODE_TABLE, Index, Index - 48 + 52)
end
buffer.writeu8(DECODE_TABLE, 43, 62)
buffer.writeu8(DECODE_TABLE, 47, 63)
end
local Padding = PADDING_CHARACTER
local InputLength = buffer.len(buff)
local Chunks = math.ceil(InputLength / 3)
local OutputLength = Chunks * 4
local Output = buffer.create(OutputLength)
local Lookup = DIRECT_LOOKUP
local DoubleChunks = math.floor((Chunks - 1) / 2)
for ChunkIndex = 1, DoubleChunks do
local InputIndex = (ChunkIndex - 1) * 6
local OutputIndex = (ChunkIndex - 1) * 8
local Word1 = bit32.byteswap(buffer.readu32(buff, InputIndex))
local Octet1_1 = bit32.rshift(Word1, 26)
local Octet1_2 = bit32.rshift(Word1, 20)
local Octet1_3 = bit32.rshift(Word1, 14)
local Octet1_4 = bit32.rshift(Word1, 8)
local Word2 = bit32.byteswap(buffer.readu32(buff, InputIndex + 3))
local Octet2_1 = bit32.rshift(Word2, 26)
local Octet2_2 = bit32.rshift(Word2, 20)
local Octet2_3 = bit32.rshift(Word2, 14)
local Octet2_4 = bit32.rshift(Word2, 8)
buffer.writeu32(Output, OutputIndex, bit32.bor(
buffer.readu8(Lookup, bit32.band(Octet1_1, 255)),
buffer.readu8(Lookup, bit32.band(Octet1_2, 255)) * 256,
buffer.readu8(Lookup, bit32.band(Octet1_3, 255)) * 65536,
buffer.readu8(Lookup, bit32.band(Octet1_4, 255)) * 16777216
))
buffer.writeu32(Output, OutputIndex + 4, bit32.bor(
buffer.readu8(Lookup, bit32.band(Octet2_1, 255)),
buffer.readu8(Lookup, bit32.band(Octet2_2, 255)) * 256,
buffer.readu8(Lookup, bit32.band(Octet2_3, 255)) * 65536,
buffer.readu8(Lookup, bit32.band(Octet2_4, 255)) * 16777216
))
end
local ProcessedChunks = DoubleChunks * 2
if ProcessedChunks < Chunks - 1 then
local InputIndex = ProcessedChunks * 3
local OutputIndex = ProcessedChunks * 4
local Word = bit32.byteswap(buffer.readu32(buff, InputIndex))
local Octet1 = bit32.rshift(Word, 26)
local Octet2 = bit32.rshift(Word, 20)
local Octet3 = bit32.rshift(Word, 14)
local Octet4 = bit32.rshift(Word, 8)
buffer.writeu32(Output, OutputIndex, bit32.bor(
buffer.readu8(Lookup, bit32.band(Octet1, 255)),
buffer.readu8(Lookup, bit32.band(Octet2, 255)) * 256,
buffer.readu8(Lookup, bit32.band(Octet3, 255)) * 65536,
buffer.readu8(Lookup, bit32.band(Octet4, 255)) * 16777216
))
end
if InputLength > 0 then
local TotalProcessedChunks = DoubleChunks * 2 + (ProcessedChunks < Chunks - 1 and 1 or 0)
local ProcessedBytes = TotalProcessedChunks * 3
local RemainingBytes = InputLength - ProcessedBytes
local LastOutputIndex = OutputLength - 4
if RemainingBytes == 3 then
if ProcessedBytes + 4 <= InputLength then
local Word = bit32.byteswap(buffer.readu32(buff, ProcessedBytes))
local Octet1 = bit32.rshift(Word, 26)
local Octet2 = bit32.rshift(Word, 20)
local Octet3 = bit32.rshift(Word, 14)
local Octet4 = bit32.rshift(Word, 8)
buffer.writeu32(Output, LastOutputIndex, bit32.bor(
buffer.readu8(Lookup, bit32.band(Octet1, 255)),
buffer.readu8(Lookup, bit32.band(Octet2, 255)) * 256,
buffer.readu8(Lookup, bit32.band(Octet3, 255)) * 65536,
buffer.readu8(Lookup, bit32.band(Octet4, 255)) * 16777216
))
else
local Byte1 = buffer.readu8(buff, ProcessedBytes)
local Byte2 = buffer.readu8(buff, ProcessedBytes + 1)
local Byte3 = buffer.readu8(buff, ProcessedBytes + 2)
local Combined = bit32.bor(bit32.lshift(Byte1, 16), bit32.lshift(Byte2, 8), Byte3)
local Octet1 = bit32.rshift(Combined, 18)
local Octet2 = bit32.band(bit32.rshift(Combined, 12), 63)
local Octet3 = bit32.band(bit32.rshift(Combined, 6), 63)
local Octet4 = bit32.band(Combined, 63)
buffer.writeu32(Output, LastOutputIndex, bit32.bor(
buffer.readu8(Lookup, Octet1),
buffer.readu8(Lookup, Octet2) * 256,
buffer.readu8(Lookup, Octet3) * 65536,
buffer.readu8(Lookup, Octet4) * 16777216
))
end
elseif RemainingBytes == 2 then
local Byte1 = buffer.readu8(buff, ProcessedBytes)
local Byte2 = buffer.readu8(buff, ProcessedBytes + 1)
local Combined = bit32.bor(bit32.lshift(Byte1, 16), bit32.lshift(Byte2, 8))
local Octet1 = bit32.rshift(Combined, 18)
local Octet2 = bit32.rshift(Combined, 12)
local Octet3 = bit32.rshift(Combined, 6)
buffer.writeu32(Output, LastOutputIndex, bit32.bor(
buffer.readu8(Lookup, bit32.band(Octet1, 255)),
buffer.readu8(Lookup, bit32.band(Octet2, 255)) * 256,
buffer.readu8(Lookup, bit32.band(Octet3, 255)) * 65536,
Padding * 16777216
))
elseif RemainingBytes == 1 then
local Byte1 = buffer.readu8(buff, ProcessedBytes)
local Combined = bit32.lshift(Byte1, 16)
local Octet1 = bit32.rshift(Combined, 18)
local Octet2 = bit32.rshift(Combined, 12)
buffer.writeu32(Output, LastOutputIndex, bit32.bor(
buffer.readu8(Lookup, bit32.band(Octet1, 255)),
buffer.readu8(Lookup, bit32.band(Octet2, 255)) * 256,
Padding * 65536,
Padding * 16777216
))
end
end
return types.singleton(buffer.tostring(Output))
end
-- Example Usage:
local Encoded: Base64<"This is a test string"> = "" -- Press tab for autocompletion!
-- Do note that autocompletion will *not* work with Fragment Autocomplete
@AstonishedLiker
Copy link

Awesome!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment