Files
wnsrc/lua/pac3/libraries/luadata.lua
lifestorm 94063e4369 Upload
2024-08-04 22:55:00 +03:00

360 lines
8.0 KiB
Lua

--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
--[[
luadata by CapsAdmin (fuck copyright, do what you want with this)
-- encodes table to string
string luadata.Encode(tbl)
-- decodes string to table
-- it will throw an error if there's a syntax error in the table
table luadata.Decode(str)
-- writes the table to file ( it's just "file.Write(path, luadata.Encode(str))" )
nil luadata.WriteFile(path, tbl)
table luadata.ReadFile(path)
-- returns a string of how the variable is typically initialized
string luadata.ToString(var)
-- will let you add your own tostring function for a custom type
-- if you have made a custom data object, you can do this "mymatrix.LuaDataType = "Matrix33""
-- and it will make luadata.Type return that instead
nil luadata.SetModifier(type, callback)
]]
--- luajit bytecode firewall --
local opcode_checker
do
local bcnames
local jit = jit or require("jit")
local ver = jit and jit.version_num or 0
-- what are these magic versions?
if ver >= 20000 and ver <= 20009 then
bcnames = "ISLT ISGE ISLE ISGT ISEQV ISNEV ISEQS ISNES ISEQN ISNEN ISEQP ISNEP ISTC ISFC IST ISF MOV NOT UNM LEN ADDVN SUBVN MULVN DIVVN MODVN ADDNV SUBNV MULNV DIVNV MODNV ADDVV SUBVV MULVV DIVVV MODVV POW CAT KSTR KCDATAKSHORTKNUM KPRI KNIL UGET USETV USETS USETN USETP UCLO FNEW TNEW TDUP GGET GSET TGETV TGETS TGETB TSETV TSETS TSETB TSETM CALLM CALL CALLMTCALLT ITERC ITERN VARG ISNEXTRETM RET RET0 RET1 FORI JFORI FORL IFORL JFORL ITERL IITERLJITERLLOOP ILOOP JLOOP JMP FUNCF IFUNCFJFUNCFFUNCV IFUNCVJFUNCVFUNCC FUNCCW"
elseif ver==20100 then -- LuaJIT 2.1.0-beta3
bcnames = "ISLT ISGE ISLE ISGT ISEQV ISNEV ISEQS ISNES ISEQN ISNEN ISEQP ISNEP ISTC ISFC IST ISF ISTYPEISNUM MOV NOT UNM LEN ADDVN SUBVN MULVN DIVVN MODVN ADDNV SUBNV MULNV DIVNV MODNV ADDVV SUBVV MULVV DIVVV MODVV POW CAT KSTR KCDATAKSHORTKNUM KPRI KNIL UGET USETV USETS USETN USETP UCLO FNEW TNEW TDUP GGET GSET TGETV TGETS TGETB TGETR TSETV TSETS TSETB TSETM TSETR CALLM CALL CALLMTCALLT ITERC ITERN VARG ISNEXTRETM RET RET0 RET1 FORI JFORI FORL IFORL JFORL ITERL IITERLJITERLLOOP ILOOP JLOOP JMP FUNCF IFUNCFJFUNCFFUNCV IFUNCVJFUNCVFUNCC FUNCCW"
end
local jutil = jit.util
if not jutil then
local ok, _jutil = pcall(require,'jit.util')
if not ok then
bcnames = nil
else
jutil = _jutil
end
end
if not bcnames then
if not jutil then
print("[luadata] Verifier could not be loaded. luadata may cause infinite loops.")
else
ErrorNoHalt"LUADATA SECURITY WARNING: Unable to load verifier, update me!\n"
end
opcode_checker = function() return function() return true end end
else
local band = bit.band
local opcodes = {}
--extract opcode names
for str in bcnames:gmatch "......" do
str = str:gsub("%s", "")
table.insert(opcodes, str)
end
local function getopnum(opname)
for k, v in next, opcodes do
if v == opname then
return k
end
end
error("not found: " .. opname)
end
local function getop(func, pc)
local ins = jutil.funcbc(func, pc)
return ins and (band(ins, 0xff)+1)
end
opcode_checker = function(white)
local opwhite = {}
for i=0,#opcodes do table.insert(opwhite, false) end
local function iswhitelisted(opnum)
local ret = opwhite[opnum]
if ret == nil then
error("opcode not found " .. opnum)
end
return ret
end
local function add_whitelist(num)
if opwhite[num] == nil then
error "invalid opcode num"
end
opwhite[num] = true
end
for line in white:gmatch '[^\r\n]+' do
local opstr_towhite = line:match '[%w]+'
if opstr_towhite and opstr_towhite:len() > 0 then
local whiteopnum = getopnum(opstr_towhite)
add_whitelist(whiteopnum)
assert(iswhitelisted(whiteopnum))
end
end
local function checker_function(func,max_opcodes)
max_opcodes = max_opcodes or math.huge
for i = 1, max_opcodes do
local ret = getop(func, i)
if not ret then
return true
end
if not iswhitelisted(ret) then
--error("non-whitelisted: " .. )
return false,"non-whitelisted: "..opcodes[ret]
end
end
return false,"checked max_opcodes"
end
return checker_function
end
end
end
local whitelist = [[TNEW
TDUP
TSETV
TSETS
TSETB
TSETM
KSTR
KCDATA
KSHORT
KNUM
KPRI
KNIL
UNM
GGET
CALL
RET1]]
local is_func_ok = opcode_checker(whitelist)
-------------------------------
local luadata = {}
local s = luadata
luadata.is_func_ok = is_func_ok
luadata.EscapeSequences = {
[("\a"):byte()] = [[\a]],
[("\b"):byte()] = [[\b]],
[("\f"):byte()] = [[\f]],
[("\t"):byte()] = [[\t]],
[("\r"):byte()] = [[\r]],
[("\v"):byte()] = [[\v]],
}
local tab = 0
luadata.Types = {
["number"] = function(var)
return ("%s"):format(var)
end,
["string"] = function(var)
return ("%q"):format(var)
end,
["boolean"] = function(var)
return ("%s"):format(var and "true" or "false")
end,
["Vector"] = function(var)
return ("Vector(%s, %s, %s)"):format(var.x, var.y, var.z)
end,
["Angle"] = function(var)
return ("Angle(%s, %s, %s)"):format(var.p, var.y, var.r)
end,
["table"] = function(var)
if
isnumber(var.r) and
isnumber(var.g) and
isnumber(var.b) and
isnumber(var.a)
then
return ("Color(%s, %s, %s, %s)"):format(var.r, var.g, var.b, var.a)
end
tab = tab + 1
local str = luadata.Encode(var, true)
tab = tab - 1
return str
end,
}
function luadata.SetModifier(type, callback)
luadata.Types[type] = callback
end
function luadata.Type(var)
local t
if IsEntity(var) then
if var:IsValid() then
t = "Entity"
else
t = "NULL"
end
else
t = type(var)
end
if t == "table" then
if var.LuaDataType then
t = var.LuaDataType
end
end
return t
end
function luadata.ToString(var)
local func = s.Types[s.Type(var)]
return func and func(var)
end
function luadata.Encode(tbl, __brackets)
if luadata.Hushed then return end
local str = __brackets and "{\n" or ""
for key, value in pairs(tbl) do
value = s.ToString(value)
key = s.ToString(key)
if key and value and key ~= "__index" then
str = str .. ("\t"):rep(tab) .. ("[%s] = %s,\n"):format(key, value)
end
end
str = str .. ("\t"):rep(tab-1) .. (__brackets and "}" or "")
return str
end
local env = {
Vector=Vector,
Angle=Angle,
Color=Color,
--Entity=Entity,
}
-- TODO: Bytecode analysis for bad loop and string functions?
function luadata.Decode(str,nojail)
local func = CompileString(string.format("return { %s }",str), "luadata_decode", false)
if isstring(func) then
--ErrorNoHalt("Luadata decode syntax: "..tostring(func):gsub("^luadata_decode","")..'\n')
return nil,func
end
if not nojail then
setfenv(func,env)
elseif istable(nojail) then
setfenv(func,nojail)
elseif isfunction(nojail) then
nojail( func )
end
local ok,err = is_func_ok( func )
if not ok or err then
err = err or "invalid opcodes detected"
--ErrorNoHalt("Luadata opcode: "..tostring(err):gsub("^luadata_decode","")..'\n')
return nil,err
end
local ok, err = xpcall(func,debug.traceback)
if not ok then
--ErrorNoHalt("Luadata decode: "..tostring(err):gsub("^luadata_decode","")..'\n')
return nil,err
end
if isfunction(nojail) then
nojail( func, err )
end
return err
end
do -- file extension
function luadata.WriteFile(path, tbl)
if tbl==nil or false --[[empty table!?]] then
if file.Exists(path,'DATA') then
file.Delete(path,'DATA')
return true
end
return false,"file does not exist"
end
local encoded = luadata.Encode(tbl)
file.Write(path, encoded)
--if not file.Exists(path,'DATA') then return false,"could not write" end
return encoded
end
function luadata.ReadFile(path,location,noinvalid)
local file = file.Read(path,location or 'DATA')
if not file then
if noinvalid then return end
return false,"invalid file"
end
return luadata.Decode(file)
end
end
return luadata