jerome@65
|
1 local M, plat, bin = {}, require("casc.platform"), require("casc.bin")
|
jerome@65
|
2 local open, tconcat, assert, error = io.open, table.concat, assert, error
|
jerome@65
|
3 local uint32_le, uint32_be = bin.uint32_le, bin.uint32_be
|
jerome@65
|
4
|
jerome@65
|
5 local string_cursor do
|
jerome@65
|
6 local function read(self, n)
|
jerome@65
|
7 local p = self.pos
|
jerome@65
|
8 self.pos = p + n
|
jerome@65
|
9 return self.str:sub(p, p+n-1)
|
jerome@65
|
10 end
|
jerome@65
|
11 function string_cursor(s)
|
jerome@65
|
12 return {str=s, read=read, pos=1}
|
jerome@65
|
13 end
|
jerome@65
|
14 end
|
jerome@65
|
15
|
jerome@65
|
16 local function decodeChunk(chunk)
|
jerome@65
|
17 local format = chunk:sub(1,1)
|
jerome@65
|
18 if format == 'N' then
|
jerome@65
|
19 return chunk:sub(2)
|
jerome@65
|
20 elseif format == 'Z' then
|
jerome@65
|
21 return plat.decompress(chunk:sub(2))
|
jerome@65
|
22 else
|
jerome@65
|
23 error('Unknown chunk format: ' .. tostring(format))
|
jerome@65
|
24 end
|
jerome@65
|
25 end
|
jerome@65
|
26 local function parseBLTE(h, dataSize)
|
jerome@65
|
27 local header = h:read(8)
|
jerome@65
|
28 assert(header:sub(1,4) == 'BLTE', 'BLTE file magic signature')
|
jerome@65
|
29 local ofs = uint32_be(header, 4)
|
jerome@65
|
30
|
jerome@65
|
31 local chunks, ret = ofs > 0 and {}
|
jerome@65
|
32 if ofs > 0 then
|
jerome@65
|
33 local n = uint32_be(h:read(4)) % 2^16
|
jerome@65
|
34 local buf, p = h:read(n*24), 0
|
jerome@65
|
35 for i=1, n do
|
jerome@65
|
36 chunks[i], p = uint32_be(buf, p), p + 24
|
jerome@65
|
37 end
|
jerome@65
|
38 for i=1, #chunks do
|
jerome@65
|
39 chunks[i] = decodeChunk(h:read(chunks[i]))
|
jerome@65
|
40 end
|
jerome@65
|
41 ret = tconcat(chunks, "")
|
jerome@65
|
42 else
|
jerome@65
|
43 ret = decodeChunk(h:read(dataSize))
|
jerome@65
|
44 end
|
jerome@65
|
45 return ret
|
jerome@65
|
46 end
|
jerome@65
|
47
|
jerome@65
|
48 function M.readArchive(path, offset)
|
jerome@65
|
49 assert(type(path) == "string" and type(offset) == "number", 'Syntax: "content" = casc.blte.readArchive("path", offset)')
|
jerome@65
|
50
|
jerome@65
|
51 local h = open(path, "rb")
|
jerome@65
|
52 h:seek("set", offset)
|
jerome@65
|
53 local blockHead = h:read(30)
|
jerome@65
|
54 local ret = parseBLTE(h, uint32_le(blockHead, 16)-30)
|
jerome@65
|
55 h:close()
|
jerome@65
|
56
|
jerome@65
|
57 return ret
|
jerome@65
|
58 end
|
jerome@65
|
59 function M.readData(str)
|
jerome@65
|
60 assert(type(str) == "string", 'Syntax: "content" = casc.blte.readContent("str")')
|
jerome@65
|
61 return parseBLTE(string_cursor(str), #str)
|
jerome@65
|
62 end
|
jerome@65
|
63
|
jerome@65
|
64 return M |