2020-06-05 12:10:48 +10:00
local mtar = { }
2021-05-26 17:07:10 +10:00
local versions = { }
versions [ 0 ] = { nlf = " >I2 " , flf = " >I2 " } -- original version format
versions [ 1 ] = { nlf = " >I2 " , flf = " >I8 " } -- extended file size format
mtar.versions = versions
2020-06-05 12:10:48 +10:00
local function cleanPath ( path )
local pt = { }
for segment in path : gmatch ( " [^/]+ " ) do
if segment == " .. " then
pt [ # pt ] = nil
elseif segment ~= " . " then
pt [ # pt + 1 ] = segment
end
end
return table.concat ( pt , " / " )
end
2021-05-26 17:07:10 +10:00
function mtar . genHeader ( fname , len , version ) -- string number -- string -- generate a header for file *fname* when provided with file length *len*
version = version or 1
return string.format ( " \255 \255 %s%s%s%s " , string.char ( version ) , string.pack ( versions [ version ] . nlf , fname : len ( ) ) , fname , string.pack ( versions [ version ] . flf , len ) )
2020-06-05 12:10:48 +10:00
end
function mtar . iter ( stream ) -- table -- function -- Given buffer *stream*, returns an iterator suitable for use with *for* that returns, for each iteration, the file name, a function to read from the file, and the length of the file.
local remain = 0
local function read ( n )
2023-08-04 20:24:18 +10:00
local rb = stream : read ( math.min ( n , remain ) ) or " "
2020-06-05 12:10:48 +10:00
remain = remain - rb : len ( )
return rb
end
return function ( )
2020-07-13 00:58:19 +10:00
while remain > 0 do
2023-08-05 10:06:05 +10:00
remain = remain - ( # stream : read ( math.min ( remain , 2048 ) ) or " " )
2020-07-13 00:58:19 +10:00
end
2021-05-26 17:07:10 +10:00
local version = 0
2021-05-26 16:15:24 +10:00
local nlen = string.unpack ( " >I2 " , stream : read ( 2 ) or " \0 \0 " )
2020-06-05 12:10:48 +10:00
if nlen == 0 then
return
2021-05-26 17:07:10 +10:00
elseif nlen == 65535 then -- versioned header
version = string.byte ( stream : read ( 1 ) )
nlen = string.unpack ( versions [ version ] . nlf , stream : read ( string.packsize ( versions [ version ] . nlf ) ) )
2020-06-05 12:10:48 +10:00
end
local name = cleanPath ( stream : read ( nlen ) )
2021-05-26 17:07:10 +10:00
remain = string.unpack ( versions [ version ] . flf , stream : read ( string.packsize ( versions [ version ] . flf ) ) )
return name , read , remain
2020-06-05 12:10:48 +10:00
end
end
return mtar