Advertisement
Guest User

BLTv2

a guest
Mar 23rd, 2021
23
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 7.80 KB | None | 0 0
  1. --[[local ffi = require("ffi")
  2. local bor = bit.bor
  3. local band = bit.band
  4. local lshift = bit.lshift
  5. local rshift = bit.rshift
  6.  
  7. ffi.cdef [[
  8.     struct blt2_table_header {
  9.         uint32_t id;
  10.         uint32_t array_len;
  11.         uint8_t flags;
  12.     };
  13.  
  14.     struct blt2_serialize_header {
  15.         char magic[4];
  16.         uint32_t entries;
  17.     };
  18. ]]
  19.  
  20. local table_flags = {
  21.  
  22. }
  23.  
  24. local tag_flags = {
  25.     internal = 1,
  26.     sign = 2,
  27. }
  28.  
  29. local tag_types = {
  30.     null = 0,
  31.     float = 1,
  32.     int = 2,
  33.     string = 3,
  34.     bool = 4,
  35.     table_ref = 5
  36. }
  37.  
  38. -- table stuff
  39.  
  40. local function flatten(tbl)
  41.     local tables_in = {{tbl=tbl, i=1}}
  42.     local tables_out = {{id=0, tbl={}}}
  43.     local tables_written = {[tbl]=0}
  44.     local function get_tbl(tbl)
  45.         if not tables_written[tbl] then
  46.             tables_written[tbl] = #tables_out
  47.             tables_out[#tables_out+1] = {id=#tables_out, tbl={}}
  48.             tables_in[#tables_in+1] = {tbl=tbl,i=#tables_out}
  49.         end
  50.         return {ref=tables_written[tbl]}
  51.     end
  52.     while #tables_in > 0 do
  53.         local tbl_i = tables_in[1].tbl
  54.         local tbl_o = tables_out[tables_in[1].i].tbl
  55.         for k, v in pairs(tbl_i) do
  56.             local nk = k
  57.             if (type(k) == "table") then
  58.                 nk = get_tbl(k)
  59.             end
  60.             local nv = v
  61.             if (type(v) == "table") then
  62.                 nv = get_tbl(v)
  63.             end
  64.             tbl_o[nk] = nv
  65.         end
  66.         table.remove(tables_in, 1)
  67.     end
  68.     return tables_out
  69. end
  70.  
  71. local function expand(tbl) -- owo wuts this
  72.     local tables_ref = {}
  73.     for i=1, #tbl do
  74.         local t = tbl[i]
  75.         tables_ref[t.id] = t.tbl
  76.     end
  77.     for i=1, #tbl do
  78.         local t = tbl[i].tbl
  79.         local dk = {}
  80.         for k, v in pairs(t) do
  81.             local nk = k
  82.             if (type(k) == "table") then
  83.                 nk = tables_ref[k.ref]
  84.                 dk[#dk+1] = k
  85.             end
  86.             local nv = v
  87.             if (type(v) == "table") then
  88.                 nv = tables_ref[v.ref]
  89.             end
  90.             t[nk] = nv
  91.         end
  92.         for i=1, #dk do
  93.             table.remove(t, dk)
  94.         end
  95.     end
  96.     for i=1, #tbl do
  97.         if (tbl[i].id == 0) then
  98.             return tbl[i].tbl
  99.         end
  100.     end
  101.     error("failed to find root")
  102. end
  103.  
  104. -- serialization
  105.  
  106. local function get_int_size(int)
  107.     --print(int)
  108.     for i=1, 8 do
  109.         --[[max = max | (0xFF << (8*(i-1)))
  110.         if (max >= int) then
  111.             return i
  112.         end]]
  113.         --print(i)
  114.         if (pcall(string.pack, "<I"..i, int)) then
  115.             return i
  116.         end
  117.     end
  118.     return 8
  119. end
  120.  
  121. local function get_int_size_s(int)
  122.     for i=1, 8 do
  123.         --[[max = max | (0xFF << (8*(i-1)))
  124.         if (max >= int) then
  125.             return i
  126.         end]]
  127.         --print(i)
  128.         if (pcall(string.pack, "<i"..i, int)) then
  129.             return i
  130.         end
  131.     end
  132.     return 8
  133. end
  134.  
  135. local function get_int(size, int)
  136.     local str = ""
  137.     --print(size)
  138.     return string.pack("<I"..size, int)
  139.     --[[for i=1, size do
  140.         str = str .. string.char(int & 0xFF)
  141.         int = (int >> 8)
  142.     end]]
  143. --  return str
  144. end
  145.  
  146. local function get_int_s(size, int)
  147.     local str = ""
  148.     str = string.pack("<i"..size, int)
  149.     return str
  150. end
  151.  
  152. local function write_tag(type, flags, data)
  153.     local dsize = #data
  154.     if (dsize <= 15) then
  155.         return string.char(type, (((flags | tag_flags.internal) << 4) | dsize))..data
  156.     end
  157.     local isize = get_int_size(dsize)
  158.     return string.char(type, ((flags << 4) | isize))..get_int(isize, dsize)..data
  159. end
  160.  
  161. local function write_nil()
  162.     return write_tag(tag_types.null, 0, "")
  163. end
  164.  
  165. local function write_int(i)
  166.     if (i < 0) then
  167.         local dsize = get_int_size_s((i))
  168.         return write_tag(tag_types.int, tag_flags.sign, get_int_s(dsize, i))
  169.     end
  170.     --print(i)
  171.     local dsize = get_int_size(i)
  172.     return write_tag(tag_types.int, 0, get_int(dsize, i))
  173. end
  174.  
  175. local function write_double(d)
  176.     --return write_tag(tag_types.float, 0, ffi.string(ffi.new("double[1]", {d}), 8))
  177.     return write_tag(tag_types.float, 0, string.pack("<d", d))
  178. end
  179.  
  180. local function write_string(s)
  181.     return write_tag(tag_types.string, 0, s)
  182. end
  183.  
  184. local function write_bool(b)
  185.     return write_tag(tag_types.bool, 0, string.char(b and 1 or 0))
  186. end
  187.  
  188. local function write_table_ref(r)
  189.     local dsize = get_int_size(r.ref)
  190.     return write_tag(tag_types.table_ref, 0, get_int(dsize, r.ref))
  191. end
  192.  
  193. local function write_value(v)
  194.     if (type(v) == "string") then
  195.         return write_string(v)
  196.     elseif (type(v) == "number") then
  197.         if (math.floor(v) ~= v or v == math.huge or v == -math.huge or v ~= v) then
  198.             return write_double(v)
  199.         else
  200.             return write_int(v)
  201.         end
  202.     elseif (type(v) == "boolean") then
  203.         return write_bool(v)
  204.     elseif (type(v) == "table") then
  205.         return write_table_ref(v)
  206.     elseif (type(v) == "nil") then
  207.         return write_nil()
  208.     end
  209.     return write_string(tostring(v))
  210. end
  211.  
  212. local function write_flattened_table(tbl)
  213.     local t = tbl.tbl
  214.     local data = ""
  215.     local entries = #t
  216.     for i=1, entries do
  217.         data = data .. write_value(t[i])
  218.     end
  219.     for k, v in pairs(t) do
  220.         --print(k, v)
  221.         if (type(k) == "number" and k <= entries) then
  222.             goto continue
  223.         end
  224.         data = data .. write_value(k) .. write_value(v)
  225.         ::continue::
  226.     end
  227.     data = data .. write_nil() .. write_nil()
  228.     --[[local header = ffi.new("struct blt2_table_header")
  229.     header.id = tbl.id
  230.     header.flags = 0
  231.     header.array_len = entries
  232.     return ffi.string(header, 9)..data]]
  233.     return string.pack("<IIB", tbl.id, entries, 0)..data
  234. end
  235.  
  236. local function serialize_table(tbl)
  237.     local flattened = flatten(tbl)
  238.     --[[local header = ffi.new("struct blt2_serialize_header")
  239.     header.entries = #flattened
  240.     header.magic = "blt2"
  241.     local data = ffi.string(header, 8)]]
  242.     local data = string.pack("<c4I", "blt2", #flattened)
  243.     for i=1, #flattened do
  244.         data = data .. write_flattened_table(flattened[i])
  245.     end
  246.     return data
  247. end
  248.  
  249. -- deserialization
  250.  
  251. local function read_int(s)
  252.     local int = 0
  253.     if #s > 0 then
  254.         int = string.unpack("<I"..#s, s)
  255.     end
  256.     return int
  257. end
  258.  
  259. local function read_int_s(s)
  260.     local int = 0
  261.     if #s > 0 then
  262.         int = string.unpack("<i"..#s, s)
  263.     end
  264.     return int
  265. end
  266.  
  267. local function decode_string(s)
  268.     return s
  269. end
  270.  
  271. local function decode_double(d)
  272.     return string.unpack("<d", d)--ffi.cast("double *", ffi.new("char[8]", d))[0]
  273. end
  274.  
  275. local function decode_bool(b)
  276.     return b ~= "\0"
  277. end
  278.  
  279. local function decode_int(b, flags)
  280.     if (flags & tag_flags.sign > 0) then
  281.         return read_int_s(b)
  282.     end
  283.     return read_int(b)
  284.     --return read_int(b)*(((flags & tag_flags.sign) > 0) and -1 or 1)
  285. end
  286.  
  287. local function decode_ref(r)
  288.     return {ref=read_int(r)}
  289. end
  290.  
  291. local dser = {
  292.     [0] = function()return nil end,
  293.     decode_double,
  294.     decode_int,
  295.     decode_string,
  296.     decode_bool,
  297.     decode_ref
  298. }
  299.  
  300. local function read_tag(state)
  301.     local header = state:read(2)
  302.     local ttype, flags_size = header:byte(1, 2)
  303.     local size = (flags_size & 0xF)
  304.     local flags = (flags_size >> 4)
  305.     local dsize
  306.     if ((flags & tag_flags.internal) > 0) then
  307.         dsize = size
  308.     else
  309.         dsize = read_int(state:read(size))
  310.     end
  311.     local data = state:read(dsize)
  312.     return (dser[ttype] or decode_string)(data, flags)
  313. end
  314.  
  315. local function read_tbl_header(state)
  316.     local id, len, flags = string.unpack("<IIB", state:read(9))
  317.     return {id=id,array_len=len,flags=flags}
  318. end
  319.  
  320. local function read_flattened_table(state)
  321.     local header = read_tbl_header(state) --ffi.cast("struct blt2_table_header *", ffi.new("char[9]", state:read(9)))[0]
  322.     local t = {}
  323.     for i=1, header.array_len do
  324.         t[i] = read_tag(state)
  325.     end
  326.     while true do
  327.         local k, v = read_tag(state), read_tag(state)
  328.         if (k == nil and v == nil) then
  329.             return {id=header.id, tbl=t}
  330.         end
  331.         t[k] = v
  332.     end
  333. end
  334.  
  335. local function read_serialize_header(state)
  336.     local magic, entries = string.unpack("<c4I", state:read(8))
  337.     return {magic=magic,entries=entries}
  338. end
  339.  
  340. local function deserialize_table(data)
  341.     local state = {
  342.         data = data,
  343.         pos = 1
  344.     }
  345.     function state:read(amt)
  346.         local s = self.data:sub(self.pos, self.pos+amt-1)
  347.         self.pos = self.pos+amt
  348.         return s
  349.     end
  350.     local header = read_serialize_header(state) --ffi.cast("struct blt2_serialize_header *", ffi.new("char[8]", state:read(8)))[0]
  351.     local parts = {}
  352.     for i=1, header.entries do
  353.         parts[i] = read_flattened_table(state)
  354.     end
  355.     return expand(parts)
  356. end
  357.  
  358. return {serialize=serialize_table, deserialize=deserialize_table}
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement