local base64 = {}
local data = mw.loadData('Dev:Base64/data')
local DECODE = data.DECODE
local ENCODE = data.ENCODE
local i18n = require('Dev:i18n').loadMessages('Base64')
local extract = require('bit32').extract
local char = string.char
local byte = string.byte
local sub = string.sub
local trim = mw.text.trim
local PAD = byte('=')
function base64.encode(str)
if str == '' then return '' end
local result = {}
local strlen = #str
local lastn = strlen % 3
local j = 0
for i = 1, strlen - lastn, 3 do
local first, second, third = byte(str, i, i + 2)
local v = first * 0x10000 + second * 0x100 + third
local a = v / 2^18 % 2^6; a = a - a % 1
local b = v / 2^12 % 2^6; b = b - b % 1
local c = v / 2^6 % 2^6; c = c - c % 1
local d = v / 2^0 % 2^6; d = d - d % 1
result[j + 1] = ENCODE[a + 1]
result[j + 2] = ENCODE[b + 1]
result[j + 3] = ENCODE[c + 1]
result[j + 4] = ENCODE[d + 1]
j = j + 4
end
if lastn == 2 then
local first, second = byte(str, strlen - 1, strlen)
local v = first * 0x10000 + second * 0x100
local a = v / 2^18 % 2^6; a = a - a % 1
local b = v / 2^12 % 2^6; b = b - b % 1
local c = v / 2^6 % 2^6; c = c - c % 1
result[j + 1] = ENCODE[a + 1]
result[j + 2] = ENCODE[b + 1]
result[j + 3] = ENCODE[c + 1]
result[j + 4] = PAD
elseif lastn == 1 then
local v = byte(str, strlen) * 0x10000
local a = v / 2^18 % 2^6; a = a - a % 1
local b = v / 2^12 % 2^6; b = b - b % 1
result[j + 1] = ENCODE[a + 1]
result[j + 2] = ENCODE[b + 1]
result[j + 3] = PAD
result[j + 4] = PAD
end
return char(unpack(result))
end
-- for the reverse compatibility
base64.encoder = base64.encode
function base64.decode(str)
str = trim(str)
if string.match(str, data.pattern) ~= nil then
return error(i18n:msg('error-ascii'))
end
if str == '' then return '' end
local result = {}
local strlen = #str
if (strlen % 4 ~= 0) then
if (strlen % 4 ~= 1) then
str = str .. string.rep('=', 4 - (strlen % 4))
else
return error(i18n:msg('error-length'))
end
end
strlen = #str
local padding = sub(str, -2) == '==' and 2 or sub(str, -1) == '=' and 1 or 0
local j = 0
for i = 1, padding > 0 and strlen - 4 or strlen, 4 do
local first, second, third, fourth = byte(str, i, i + 4)
local v = DECODE[first+1] * 0x40000 + DECODE[second+1] * 0x1000 + DECODE[third+1] * 0x40 + DECODE[fourth+1]
local a = v / 2^16 % 2^8; a = a - a % 1
local b = v / 2^8 % 2^8; b = b - b % 1
local c = v / 2^0 % 2^8; c = c - c % 1
result[j + 1] = a
result[j + 2] = b
result[j + 3] = c
j = j + 3
end
if padding == 1 then
local first, second, third = byte(str, strlen - 3, strlen - 1)
local v = DECODE[first+1] * 0x40000 + DECODE[second+1] * 0x1000 + DECODE[third+1] * 0x40
local a = v / 2^16 % 2^8; a = a - a % 1
local b = v / 2^8 % 2^8; b = b - b % 1
result[j + 1] = a
result[j + 2] = b
elseif padding == 2 then
local first, second = byte(str, strlen - 3, strlen - 2)
local v = DECODE[first+1] * 0x40000 + DECODE[second+1] * 0x1000
local a = v / 2^16 % 2^8; a = a - a % 1
result[j + 1] = a
end
return char(unpack(result))
end
-- for the reverse compatibility
base64.decoder = base64.decode
return base64