forked from osmarks/potatOS
158 lines
3.1 KiB
Lua
158 lines
3.1 KiB
Lua
local function chars(str)
|
|
local pos = 1
|
|
return function()
|
|
if pos <= #str then
|
|
local pos_was = pos
|
|
pos = pos + 1
|
|
return str:sub(pos_was, pos_was), pos_was
|
|
end
|
|
end
|
|
end
|
|
|
|
-- from lua users wiki - magic
|
|
local function unpackbits(num, width)
|
|
local fl = {}
|
|
local rem
|
|
for i = 1,width do
|
|
num,rem = math.modf(num/2)
|
|
fl[#fl+1] = rem>=0.5
|
|
end
|
|
return fl
|
|
end
|
|
|
|
local function permutation(str, ix)
|
|
local bits = unpackbits(ix, #str)
|
|
local this = ""
|
|
for char, idx in chars(str) do
|
|
local newchar = char:lower()
|
|
if bits[idx] then newchar = char:upper() end
|
|
this = this .. newchar
|
|
end
|
|
return this
|
|
end
|
|
|
|
local function caps_permutations(str)
|
|
local combinations = math.pow(2, #str) - 1
|
|
local ret = {}
|
|
for i = 0, combinations do
|
|
table.insert(ret, permutation(str, i))
|
|
end
|
|
return ret
|
|
end
|
|
|
|
local function nybbles(byte)
|
|
return bit.brshift(bit.band(0xF0, byte), 4), bit.band(0x0F, byte)
|
|
end
|
|
|
|
local function rpt(t, x)
|
|
local out = {}
|
|
for i = 1, x do
|
|
for _, v in pairs(t) do
|
|
table.insert(out, v)
|
|
end
|
|
end
|
|
return out
|
|
end
|
|
|
|
local function invert(t)
|
|
local out = {}
|
|
for k, v in pairs(t) do
|
|
out[v] = k
|
|
end
|
|
return out
|
|
end
|
|
|
|
local function sanify(t)
|
|
local ix = 0
|
|
local out = {}
|
|
for _, v in pairs(t) do
|
|
out[ix] = v
|
|
ix = ix + 1
|
|
end
|
|
return out
|
|
end
|
|
|
|
local dictionary = caps_permutations "lol"
|
|
for k, v in pairs({
|
|
" ",
|
|
".",
|
|
"?",
|
|
"!",
|
|
"#",
|
|
",",
|
|
";",
|
|
":"
|
|
}) do table.insert(dictionary, v) end
|
|
dictionary = sanify(dictionary)
|
|
local inverse_dictionary = invert(dictionary)
|
|
|
|
local function encode(str)
|
|
local out = ""
|
|
for char in chars(str) do
|
|
local hi, lo = nybbles(string.byte(char))
|
|
out = out .. dictionary[hi] .. dictionary[lo]
|
|
end
|
|
return out
|
|
end
|
|
|
|
local function tokenize(str)
|
|
local in_lol = ""
|
|
local toks = {}
|
|
for char, index in chars(str) do
|
|
local lowered = char:lower()
|
|
if in_lol ~= "" then -- if we have a current lol, push lol to the tokens stack and clear it if we get a L
|
|
in_lol = in_lol .. char
|
|
if lowered == "l" then
|
|
table.insert(toks, in_lol)
|
|
in_lol = ""
|
|
elseif lowered == "o" then
|
|
else error "Invalid character in LOL" end
|
|
else
|
|
if lowered == "l" then
|
|
in_lol = char
|
|
else
|
|
table.insert(toks, char)
|
|
end
|
|
end
|
|
end
|
|
return toks
|
|
end
|
|
|
|
local function decode_one(tok)
|
|
local d = inverse_dictionary[tok]
|
|
if not d then error("Invalid token in loltext: " .. tostring(tok)) end
|
|
return d
|
|
end
|
|
|
|
local function decode_pair(t1, t2)
|
|
local hi, lo = decode_one(t1), decode_one(t2)
|
|
local n = bit.bor(bit.blshift(hi, 4), lo)
|
|
return string.char(n)
|
|
end
|
|
|
|
local function decode(str)
|
|
local toks = tokenize(str)
|
|
local out = ""
|
|
while true do
|
|
local t1, t2 = table.remove(toks, 1), table.remove(toks, 1)
|
|
if not t1 or not t2 then
|
|
break
|
|
else
|
|
out = out .. decode_pair(t1, t2)
|
|
end
|
|
end
|
|
return out
|
|
end
|
|
|
|
local function repeat_function(f, times)
|
|
return function(data, times_)
|
|
local times = times_ or times
|
|
local d = data
|
|
for i = 1, times do
|
|
d = f(d)
|
|
end
|
|
return d
|
|
end
|
|
end
|
|
|
|
return { encode = repeat_function(encode, 1), decode = repeat_function(decode, 1) } |