-- module for reading serialized lua bytecode local bit=require('bit') local HEADER_MAGIC = {27, string.byte('L'), string.byte('J')} local HEADER_FLAG_STRIP = 0x02 local function read_u8(fp) return string.byte(fp:read(1)) end local function read_u16(fp) -- TODO: endianess local b1 = read_u8(fp) local b2 = read_u8(fp) return bit.bor(b2*0x100, b1) end local function read_u32(fp) -- TODO: endianess local h1 = read_u16(fp) local h2 = read_u16(fp) return bit.bor(h2*0x10000, h1) end local function read_u8n(fp, n) return { string.byte(fp:read(n), 1, n) } end local function read_u16n(fp, n) local res = {} for i = 1, n do res[i] = read_u16(fp) end return res end local function read_u32n(fp, n) local res = {} for i = 1, n do res[i] = read_u32(fp) end return res end local function read_uleb128(fp) local last_byte = false local res = 0 local shift = 0 -- the bytes are read from the LSB to the MSB while not last_byte do local uleb_byte = read_u8(fp) res = bit.bor(res, bit.lshift(bit.band(uleb_byte, 0x7f), shift)) if bit.band(uleb_byte, 0x80) == 0 then last_byte = true end end return res end local function read_header(fp) local magic = read_u8n(fp, 3) local version = read_u8(fp) local flags = read_uleb128(fp) local name if bit.band(flags, HEADER_FLAG_STRIP) ~= 0 then name = '' else local nameLen = read_uleb128(fp) name = fp:read(nameLen) end return { magic = magic, version = version, flags = flags, name = name, } end local function read_proto(fp) local length = read_uleb128(fp) -- if the the last read proto was the last one -- we have reached the end marker, which is a zero -- this overlaps with a uleb128 zero representation if length == 0 then return end -- read proto header local flags = read_u8(fp) local numparams = read_u8(fp) local framesize = read_u8(fp) local numuv = read_u8(fp) local numkgc = read_uleb128(fp) local numkn = read_uleb128(fp) local numbc = read_uleb128(fp) local debugLen = 0 local debugInfo = nil if bit.band(flags, HEADER_FLAG_STRIP) ~= 0 then debugLen = read_uleb128(fp) -- TODO: is this correct? if debugLen ~= 0 then local firstLine = read_uleb128(fp) local numLine = read_uleb128(fp) debugInfo = { firstLine = firstLine, numLine = numLine, } end end local bcins = read_u32n(fp, numbc) local uvdata = read_u16n(fp, numuv) -- local kgc -- local numkn return { flags = flags, numparams = numparams, framesize = framesize, numuv = numuv, numkgc = numkgc, numkn = numkn, numbc = numbc, debugInfo = debugInfo, bcins = bcins, uvdata = uvdata, } end return { read_header = read_header, read_proto = read_proto, }