-- Source: http://lua-users.org/wiki/BaseSixtyFour
-- Lua 5.1+ base64 v3.0 (c) 2009 by Alex Kloss <alexthkloss@web.de>
-- licensed under the terms of the LGPL2

local M = {}

-- character table string
local b = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

-- encoding
function M.enc(data)
  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

-- encoding base64url
function M.encurl(data)
  return M.enc(data):gsub('+', '-'):gsub('/', '_')
end

-- decoding
function M.dec(data)
  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

-- decoding base64url
function M.decurl(data)
  return M.dec(data):gsub('-', '+'):gsub('_', '/')
end

return M
