Skip to content

Instantly share code, notes, and snippets.

@Rami-Sabbagh
Last active July 5, 2020 17:03
Show Gist options
  • Save Rami-Sabbagh/f656f5c1a118f77c3b7a08f4c65efaaf to your computer and use it in GitHub Desktop.
Save Rami-Sabbagh/f656f5c1a118f77c3b7a08f4c65efaaf to your computer and use it in GitHub Desktop.
A lua library that converts tables to Lua code that can be saved
local LuaTable = {
_VERSION = 'LuaTable v1.0.2 2016/08/27',
_AUTHOR = 'RamiLego4Game',
_URL = 'https://gist.github.com/RamiLego4Game/f656f5c1a118f77c3b7a08f4c65efaaf',
_DESCRIPTION = 'A library that converts tables to Lua code that can be saved',
_LICENSE = [[
MIT LICENSE
Copyright (c) 2016 Rami Sabbagh
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
]]
}
--[[A library that converts tables to Lua code that can be saved.
Since it uses Lua to save the data, It's able to save functions ! by dumping them, But they won't be readable, only loadable, unless if you decompile them.
And moreover you can do some hand written tables with smart data generation..
The bad thing that it's less secure (you are running code) .., So load the files using this Library to sandbox the files
usage:
luacode (string) = LuaTable.encode(<variable>,[funcBehave],[standalone])
luacode (string) = LuaTable.encode_pretty(<variable>,[funcBehave],[standalone])
variable = LuaTable.decode(<luacode>,[smart])
variable (list above):
Supported types: nil,boolean,string,number,table,function,userdata
funcBehave (string or nil):
"dump" to dump the functions so they can be loaded again, But not recomended.
"name" to use tostring on the function, I guess it's useless, unless if it's used to debug something like the _G var.
"skip" (default) to skip the functions and not include them in the table.
standalone (boolean or nil):
If this is true, the result code will include a function called c (short for combine) used to combine arrays with tables (to save file lenght).
Enable this to make the result code run without using this library.
luacode (string):
The code made with LuaTable library.
smart (boolean or nil):
To give the table code the access to some usefull gloabl libraries (like math, string, ..[list above]).
example:
local LuaTable = require("LuaTable")
love.filesystem.write("TestTable.lua",LuaTable.encode({test=true}))
local TableCode = love.filesystem.read("TestTable.lua")
local TabelData = LuaTable.decode(TableCode)
list of available global vars for the table (Changable down):
Normal: pairs, ipairs, c (combine function)
Smart: pairs, ipairs, string, table, bit, math, c (combine function), love.math (if library is used in love with love.math enabled)
note: all Userdata variables can't be dumped so they will be ignored.
]]
--[[Changelog:
2017/08/25 V1.0.2: Fixed a typo in the library.
2016/08/07 V1.0.1: All Credit goes to ivan [In Love2D forums] for this update
1. Fixed a problem in LuaTable.isArray that causes arrays with gaps to encode as normal table.
2. Improved LuaTable.encode_string to use string.format instead of multiline string.
2016/08/26 V1.0.0: First Public Release
]]
local function combine(t1,t2) for k,v in pairs(t2) do t1[k] = v end return t1 end
--Config--
local prettyTabbing = "\t"
--Change the global vars here--
local normalGVars = {pairs=pairs,ipairs=ipairs,c=combine} --Used when smart argument is false or nil
local smartGVars = {pairs=pairs,ipairs=ipairs,string=string,table=table,bit=bit,math=math,c=combine} --Used when smart argument is true
if love and love.math then smartGVars.love = {math=love.math} end
--Library code starts here--
function LuaTable.encode(var,funcBehave,standalone)
if not (type(funcBehave)=="string" or type(funcBehave)=="nil") then return error("Bad argument #2 to 'LuaTable.encode' (string/nil expected, got"..type(funcBehave)..")") end
if not (type(standalone)=="boolean" or type(standalone)=="nil") then return error("Bad argument #3 to 'LuaTable.encode' (boolean/nil expected, got"..type(funcBehave)..")") end
local code = "return "
if standalone then code = "local function c(t1,t2) for k,v in pairs(t2) do t1[k] = v end return t1 end\n"..code end
local vx = "nil" if LuaTable["encode_"..type(var)] then vx = LuaTable["encode_"..type(var)](var) else print("[LuaTable] Warning, LuaTable doesn't support "..type(var)) end
code = code..vx
return code
end
function LuaTable.encode_pretty(var,funcBehave,standalone)
if not (type(funcBehave)=="string" or type(funcBehave)=="nil") then return error("Bad argument #2 to 'LuaTable.encode_pretty' (string/nil expected, got"..type(funcBehave)..")") end
if not (type(standalone)=="boolean" or type(standalone)=="nil") then return error("Bad argument #3 to 'LuaTable.encode_pretty' (boolean/nil expected, got"..type(funcBehave)..")") end
local code = "return "
if standalone then code = "local function c(t1,t2)\n for k,v in pairs(t2) do\n t1[k] = v\n end\n return t1\nend\n\n"..code end
local vx = "nil" if LuaTable["encode_"..type(var)] then vx = LuaTable["encode_"..type(var)](var,prettyTabbing,funcBehave) else print("[LuaTable] Warning, LuaTable doesn't support "..type(var)) end
code = code..vx
return code
end
function LuaTable.decode(codeString,smart)
if not (type(codeString)=="string") then return error("Bad argument #1 to 'LuaTable.decode' (string expected, got"..type(codeString)..")") end
if not (type(smart)=="boolean" or type(smart)=="nil") then return error("Bad argument #2 to 'LuaTable.decode' (boolean/nil expected, got"..type(smart)..")") end
local function combine(t1,t2) for k,v in pairs(t2) do t1[k] = v end return t1 end
local codeFunc = loadstring(codeString)
if smart then setfenv(codeFunc,smartGVars) else setfenv(codeFunc,normalGVars) end
return codeFunc()
end
function LuaTable.isArray(tabl)
local n = 0
for _ in pairs(tabl) do
n = n + 1
end
return #tabl == n
end
--[[Here you can add your own variable types.
Array is a numeric table.]]
function LuaTable.encode_array(table,pretty,funcBehave)
local s = "{"
for i=1,#table do
if pretty then
local vx = "nil" if LuaTable["encode_"..type(table[i])] then vx = LuaTable["encode_"..type(table[i])](table[i],pretty.." ",funcBehave) else print("[LuaTable] Warning, LuaTable doesn't support "..type(var)) end
if i==1 then
s = s..pretty..vx
else
s = s..",\n"..pretty..vx
end
else
local vx = "nil" if LuaTable["encode_"..type(table[i])] then vx = LuaTable["encode_"..type(table[i])](table[i],nil,funcBehave) else print("[LuaTable] Warning, LuaTable doesn't support "..type(var)) end
if i==1 then
s = s..vx
else
s = s..","..vx
end
end
end
return s.."}"
end
function LuaTable.encode_table(table,pretty,funcBehave)
if LuaTable.isArray(table) then return LuaTable.encode_array(table,pretty) end
local nums, first = {}, true
local s = "{"
for k,v in pairs(table) do
if pretty then
local vx = "nil" if LuaTable["encode_"..type(v)] then vx = LuaTable["encode_"..type(v)](v,pretty.." ",funcBehave) else print("[LuaTable] Warning, LuaTable doesn't support "..type(var)) end
if type(k) == "number" then
nums[k] = v
elseif first then
s = s.."\n"..pretty..tostring(k).." = "..vx
first = false
else
s = s..",\n"..pretty..tostring(k).." = "..vx
end
else
local vx = "nil" if LuaTable["encode_"..type(v)] then vx = LuaTable["encode_"..type(v)](v,nil,funcBehave) else print("[LuaTable] Warning, LuaTable doesn't support "..type(var)) end
if type(k) == "number" then
nums[k] = v
elseif first then
s = s..tostring(k).."="..vx
first = false
else
s = s..","..tostring(k).."="..vx
end
end
end
if #nums > 0 then
if pretty then
s = "c("..s.."},"..LuaTable.encode_array(nums,pretty.." ")..")"
else
s = "c("..s.."},"..LuaTable.encode_array(nums)..")"
end
else
s = s.."}"
end
return s
end
function LuaTable.encode_function(func,pretty,funcBehave)
local fmode = funcBehave or "skip"
if fmode == "dump" then return string.dump(func)
elseif fmode == "name" then return '"'..tostring(func)..'"'
else return "nil" end
end
function LuaTable.encode_userdata(ud,pretty,funcBehave)
if funcBehave and (funcBehave == "name" or funcBehave == "dump") then return '"'..tostring(ud)..'"' else return "nil" end
end
function LuaTable.encode_nil()
return "nil"
end
function LuaTable.encode_string(str)
return string.format("%q", str)
end
function LuaTable.encode_number(number)
return tostring(number)
end
function LuaTable.encode_boolean(boolean)
if boolean then
return "true"
else
return "false"
end
end
return LuaTable
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment