-- 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