Module:base64

From Wiktionary, the free dictionary
Jump to navigation Jump to search

This module implements the base64 encoding scheme.


local export = {}
-- use bit32 for bitwise operations
local bit32 = require("bit32")

do local chr, ord, gsub, sub = string.char, string.byte, string.gsub, string.sub

local b64t = {
	[0] =
	'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',
	'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',
	'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
}
local b64r = {}
for k, v in pairs(b64t) do b64r[v] = k end

function export.encode(data)
	return (gsub(data, '..?.?', function (m)
		local b0, b1, b2 = ord(m, 1, 3)

		if not b1 then
			local c0 = bit32.rshift(b0, 2)
			local c1 = bit32.lshift(bit32.band(b0,  3), 4)
			return b64t[c0] .. b64t[c1] .. '=='
		elseif not b2 then
			local c0 = bit32.rshift(b0, 2)
			local c1 = bit32.lshift(bit32.band(b0,  3), 4) + bit32.rshift(b1, 4)
			local c2 = bit32.lshift(bit32.band(b1, 15), 2)
			return b64t[c0] .. b64t[c1] .. b64t[c2] .. '='
		else
			local c0 = bit32.rshift(b0, 2)
			local c1 = bit32.lshift(bit32.band(b0,  3), 4) + bit32.rshift(b1, 4)
			local c2 = bit32.lshift(bit32.band(b1, 15), 2) + bit32.rshift(b2, 6)
			local c3 = bit32.band(b2, 63)
			return b64t[c0] .. b64t[c1] .. b64t[c2] .. b64t[c3]
		end
	end))
end

function export.decode(data)
    local padding = false
    if #data % 4 ~= 0 then
        error('Invalid base64')
    end
	return (gsub(data, '(.)(.)(.)(.)', function (c0, c1, c2, c3)
        local t0, t1, t2, t3 = b64r[c0], b64r[c1], b64r[c2], b64r[c3]

        if padding then
            error('Invalid base64')
        end
        if c2 == '=' and c3 == '=' then
            if not t0 or not t1 then error('Invalid base64') end
            local b0 = bit32.lshift(t0, 2) + bit32.rshift(t1, 4)
            padding = true
            return chr(b0)
        elseif c3 == '=' then
            if not t0 or not t1 or not t2 then error('Invalid base64') end
            local b0 = bit32.lshift(t0, 2) + bit32.rshift(t1, 4)
            local b1 = bit32.band(bit32.lshift(t1, 4) + bit32.rshift(t2, 2), 255)
            padding = true
            return chr(b0) .. chr(b1)
        else
            if not t0 or not t1 or not t2 or not t3 then error('Invalid base64') end
            local b0 = bit32.lshift(t0, 2) + bit32.rshift(t1, 4)
            local b1 = bit32.band(bit32.lshift(t1, 4) + bit32.rshift(t2, 2), 255)
            local b2 = bit32.band(bit32.lshift(t2, 6) + t3                 , 255)
            return chr(b0) .. chr(b1) .. chr(b2)
        end
	end))
end

end

export.enc = export.encode
export.dec = export.decode

return export