Base64 Encoding and Decoding in Lua

-- this function converts a string to base64
function to_base64(data)
    local b = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
    return ((data:gsub('.', function(x) 
        local r,b='',x:byte()
        for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end
        return r;
    end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x)
        if (#x < 6) then return '' end
        local c=0
        for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end
        return b:sub(c+1,c+1)
    end)..({ '', '==', '=' })[#data%3+1])
end
 
-- this function converts base64 to string
function from_base64(data)
    local b = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
    data = string.gsub(data, '[^'..b..'=]', '')
    return (data:gsub('.', function(x)
        if (x == '=') then return '' end
        local r,f='',(b:find(x)-1)
        for i=6,1,-1 do r=r..(f%2^i-f%2^(i-1)>0 and '1' or '0') end
        return r;
    end):gsub('%d%d%d?%d?%d?%d?%d?%d?', function(x)
        if (#x ~= 8) then return '' end
        local c=0
        for i=1,8 do c=c+(x:sub(i,i)=='1' and 2^(8-i) or 0) end
        return string.char(c)
    end))
end
 
-- usage
local data = "this is a test"
local encoded = to_base64(data)
print(encoded) -- dGhpcyBpcyBhIHRlc3Q=
local decoded = from_base64(encoded)
print(decoded) -- this is a test

The above script contains functions for converting a string to base64 and vice versa. To use these functions, simply call to_base64() or from_base64() with the string as an argument.

30 Likes

Thanks, I used this to make this other function which stores and loads CFrames from a base64 string compactly:

--Base64 serial encode CFrame
local function SerializeCFrame(cf : CFrame)	
	local function SerializeVector(vec : Vector3)
		return string.pack("f", vec.X) .. string.pack("f", vec.Y) .. string.pack("f", vec.Z)
	end
	
	--Don't need to save Z vector as we can calculate it from the other two
	local allbytes = SerializeVector(cf.XVector) .. SerializeVector(cf.YVector) .. SerializeVector(cf.Position)

	return to_base64(allbytes)
end

local function DeserializeCFrame(cfs : string)
	local bytes = from_base64(cfs)
	
	local function DeserializeVector(bytes)
		local xbytes = bytes:sub(1,4)
		local ybytes = bytes:sub(5,8)
		local zbytes = bytes:sub(9,12)
		
		return Vector3.new(string.unpack("f", xbytes), string.unpack("f", ybytes), string.unpack("f", zbytes))
	end
	
	local x = DeserializeVector(bytes:sub(1,12))
	local y = DeserializeVector(bytes:sub(13,24))
	local z = x:Cross(y)
	local p = DeserializeVector(bytes:sub(25,36))
	
	return CFrame.fromMatrix(p, x, y, z)
end

Example output

Gj08M73Pfy4AAIC/AACAv/D/gjUaPTyzAAAAAAAAAAAAAIC/
<->
CFrame.new(0, 0, -1, 4.38277326e-08, -1, 9.76024239e-07, 5.81647959e-11, 9.76024239e-07, 1, -1, -4.38277326e-08, 5.82075742e-11)