clua-0.1: parse-bin.lua
-- Goes together with the struct wrapper generator.
-- Tools
local function table_copy(t)
local u = { }
for k, v in pairs(t) do u[k] = v end
return setmetatable(u, getmetatable(t))
end
parse = {}
-- Wrap table as abstract stream.
function parse.array2stream(arr)
if (arr) then
local i = 0
return
function()
i = i + 1
return arr[i]
end
else
-- Allow arr to be nil in case we assume it's a stream of zeros.
return
function()
return 0
end
end
end
-- Parsers for "int", "float", "struct", "array"
function parse.int(stream, structs, signed, bits)
local bytes = bits/8
local accu = 0
local shift = 1
local byte = 0
while (bytes > 0) do
byte = assert(stream())
accu = accu + shift * byte;
shift = shift * 0x100
bytes = bytes - 1
end
if ((signed == 'S') and (byte > 0x7F)) then
accu = accu - shift
end
return accu
end
function parse.float()
assert(nil) -- FIXME
end
function parse.struct(stream, structs, struct_name)
return parse.table(stream, structs, structs[struct_name])
end
function parse.array(stream, structs, size, type_spec)
if (size == 0) then
return {}
else
local arr = {}
for i=1, size do
arr[i] = parse.type(stream, structs, type_spec)
end
return arr
end
end
-- Element dispatcher.
function parse.type(stream, structs, type_spec)
local spec = table_copy(type_spec)
local type = assert(table.remove(spec,1))
-- print (type)
local fun = assert(parse[type])
return fun(stream, structs, table.unpack(spec))
end
-- Table dispatcher
function parse.table(stream, structs, tab_spec)
local tab = {}
for i,rec_spec in pairs(tab_spec) do
local type_spec, name = table.unpack(rec_spec)
tab[name] = parse.type(stream, structs, type_spec)
end
return tab
end
-- Functional interface
function parse.array2table (array, structs, tab_spec)
return parse.table (parse.array2stream(array), structs, tab_spec)
end
-- Wrap table as abstract stream.
unparse = {}
function unparse.array2stream(t)
return
function(byte)
table.insert(t, byte)
end
end
function unparse.int(stream, val, structs, signed, bits)
local bytes = bits/8
local accu = val
while (bytes > 0) do
local byte = accu % 0x100
stream(byte)
accu = math.floor(accu / 0x100)
bytes = bytes - 1
end
end
function unparse.struct(stream, val, structs, struct_name)
unparse.table(stream, val, structs, structs[struct_name])
end
function unparse.array(stream, arr, structs, size, type_spec)
if (size > 0) then
for i=1,size do
unparse.type(stream, arr[i], structs, type_spec)
end
end
end
function unparse.type(stream, val, structs, type_spec)
local spec = table_copy(type_spec)
local type = assert(table.remove(spec,1))
-- print (type)
unparse[type](stream, val, structs, table.unpack(spec))
end
function unparse.table(stream, tab, structs, tab_spec)
for i,rec_spec in pairs(tab_spec) do
local type_spec, name = table.unpack(rec_spec)
unparse.type(stream, tab[name], structs, type_spec)
end
end
-- Functional interface
function unparse.table2array(tab, structs, tab_spec)
local arr = {}
unparse.table(unparse.array2stream(arr), tab, structs, tab_spec)
return arr
end