jerome@65: local M, plat, bin = {}, require("casc.platform"), require("casc.bin") jerome@65: local open, tconcat, assert, error = io.open, table.concat, assert, error jerome@65: local uint32_le, uint32_be = bin.uint32_le, bin.uint32_be jerome@65: jerome@65: local string_cursor do jerome@65: local function read(self, n) jerome@65: local p = self.pos jerome@65: self.pos = p + n jerome@65: return self.str:sub(p, p+n-1) jerome@65: end jerome@65: function string_cursor(s) jerome@65: return {str=s, read=read, pos=1} jerome@65: end jerome@65: end jerome@65: jerome@65: local function decodeChunk(chunk) jerome@65: local format = chunk:sub(1,1) jerome@65: if format == 'N' then jerome@65: return chunk:sub(2) jerome@65: elseif format == 'Z' then jerome@65: return plat.decompress(chunk:sub(2)) jerome@65: else jerome@65: error('Unknown chunk format: ' .. tostring(format)) jerome@65: end jerome@65: end jerome@65: local function parseBLTE(h, dataSize) jerome@65: local header = h:read(8) jerome@65: assert(header:sub(1,4) == 'BLTE', 'BLTE file magic signature') jerome@65: local ofs = uint32_be(header, 4) jerome@65: jerome@65: local chunks, ret = ofs > 0 and {} jerome@65: if ofs > 0 then jerome@65: local n = uint32_be(h:read(4)) % 2^16 jerome@65: local buf, p = h:read(n*24), 0 jerome@65: for i=1, n do jerome@65: chunks[i], p = uint32_be(buf, p), p + 24 jerome@65: end jerome@65: for i=1, #chunks do jerome@65: chunks[i] = decodeChunk(h:read(chunks[i])) jerome@65: end jerome@65: ret = tconcat(chunks, "") jerome@65: else jerome@65: ret = decodeChunk(h:read(dataSize)) jerome@65: end jerome@65: return ret jerome@65: end jerome@65: jerome@65: function M.readArchive(path, offset) jerome@65: assert(type(path) == "string" and type(offset) == "number", 'Syntax: "content" = casc.blte.readArchive("path", offset)') jerome@65: jerome@65: local h = open(path, "rb") jerome@65: h:seek("set", offset) jerome@65: local blockHead = h:read(30) jerome@65: local ret = parseBLTE(h, uint32_le(blockHead, 16)-30) jerome@65: h:close() jerome@65: jerome@65: return ret jerome@65: end jerome@65: function M.readData(str) jerome@65: assert(type(str) == "string", 'Syntax: "content" = casc.blte.readContent("str")') jerome@65: return parseBLTE(string_cursor(str), #str) jerome@65: end jerome@65: jerome@65: return M