124 lines
2.8 KiB
Lua
124 lines
2.8 KiB
Lua
local magic = 0x5f7d
|
|
local magic_rev = 0x7d5f
|
|
local header = "I2I2I2I2I2I6I6"
|
|
|
|
local function read_header(dat)
|
|
local e = "<"
|
|
local m = string.unpack("<I2", dat)
|
|
if m ~= magic and m ~= magic_rev then return nil, "bad magic" end
|
|
if m ~= magic then
|
|
e = ">"
|
|
end
|
|
local ent = {}
|
|
ent.magic, ent.namesize, ent.mode, ent.uid, ent.gid, ent.filesize, ent.mtime = string.unpack(e..header_fmt, dat)
|
|
return ent
|
|
end
|
|
|
|
local arc = {}
|
|
|
|
function arc:read(path)
|
|
for i=1, #self.tbl do
|
|
if (self.tbl[i].name == path and self.tbl[i].mode & 32768 > 0) then
|
|
self.seek(self.tbl[i].pos-self.seek(0))
|
|
return self.read(self.tbl[i].filesize), self.tbl[i]
|
|
end
|
|
end
|
|
return nil, "file not found"
|
|
end
|
|
|
|
function arc:exists(path)
|
|
for i=1, #self.tbl do
|
|
if (self.tbl[i].name == path) then
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
function arc:list(path)
|
|
if path:sub(#path) ~= "/" then path = path .. "/" end
|
|
local ent = {}
|
|
for i=1, #self.tbl do
|
|
if (self.tbl[i].name:sub(1, #path) == path and not self.tbl[i].name:find("/", #path+1, false)) then
|
|
ent[#ent+1] = self.tbl[i].name
|
|
end
|
|
end
|
|
return ent
|
|
end
|
|
|
|
function arc:meta(path)
|
|
for i=1, #self.tbl do
|
|
if (self.tbl[i].name == path) then
|
|
return self.tbl[i]
|
|
end
|
|
end
|
|
return nil, "file not found"
|
|
end
|
|
|
|
function arc:stream(path)
|
|
for i=1, #self.tbl do
|
|
if (self.tbl[i].name == path) then
|
|
return kio.create_stream({dev=self.dev, start=self.tbl[i].pos, size=self.tbl[i].filesize, pos=1}, {
|
|
read = function(self, amt)
|
|
self.dev:seek("set", self.pos+self.start-1)
|
|
if (self.pos+amt-1 > self.size) then
|
|
amt = self.size-self.pos
|
|
end
|
|
local dat = self.dev:read(amt)
|
|
self.pos = self.pos + #dat
|
|
return dat
|
|
end,
|
|
seek = function(self, whence, amt)
|
|
self.pos = kio.calc_seek(whence, amt, self.size, self.pos)
|
|
return self.pos
|
|
end,
|
|
write = function(self)
|
|
return kio.get_error(kio.errno.UNSUPPORTED_OPERATION)
|
|
end,
|
|
close = function(self)
|
|
|
|
end
|
|
})
|
|
end
|
|
end
|
|
end
|
|
|
|
function arc:trailer()
|
|
self.dev:seek("set", self.tbl.trailer.pos)
|
|
return self.dev:read(self.tbl.trailer.filesize)
|
|
end
|
|
|
|
function arc:close()
|
|
self.close()
|
|
end
|
|
|
|
return {
|
|
read = function(dev)
|
|
local function read(a)
|
|
return dev:read(a)
|
|
end
|
|
local function seek(a)
|
|
return dev:seek("cur", a)
|
|
end
|
|
local function close()
|
|
return dev:close()
|
|
end
|
|
local start = seek(0)
|
|
local tbl = {}
|
|
local lname = ""
|
|
while lname ~= "TRAILER!!!" do
|
|
local dat = read(22)
|
|
local et = read_header(dat)
|
|
et.name = read(et.namesize)
|
|
et.pos = seek(et.namesize & 1)
|
|
seek(et.filesize + (et.filesize & 1))
|
|
lname = et.name
|
|
if lname ~= "TRAILER!!!" then
|
|
tbl[#tbl+1] = et
|
|
else
|
|
tbl.trailer = et
|
|
end
|
|
end
|
|
return setmetatable({tbl = tbl, read = read, seek = seek, close = close, dev=dev, start=true}, {__index=arc})
|
|
end
|
|
} |