local mtar = {} -- detect OS hopefully if _OSVERSION then if _OSVERSION:sub(1,8) == "OpenOS" then OPENOS = true elseif _OSVERSION:sub(1,9) == "PsychOS" then PSYCHOS = true end else LINUX = true end local function mkdir(dir) if OPENOS or LINUX then os.execute("mkdir "..dest.."/"..dir.." &> /dev/null") elseif PSYCHOS then -- todo: write PsychOS support end end local function toint(s) s=s or "" local n = 0 local i = 1 while true do local p = s:sub(i,i) if p == "" then break end local b = string.byte(p) n = n << 8 n = n | b i=i+1 end return n end local function cint(n,l) local t={} for i = 0, 7 do t[i+1] = (n >> (i * 8)) & 0xFF end return string.reverse(string.char(table.unpack(t)):sub(1,l)) end 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 function mtar.genHeader(fname,len) -- generate a header for file *fname* when provided with file length *len* return string.format("%s%s%s",cint(fname:len(),2),fname,cint(len,2)) end function mtar.unarchive(stream,dest) dest = dest or "." mkdir(dest) while true do local nlen = toint(stream:read(2)) if nlen == 0 then break end local name = cleanPath(stream:read(nlen)) local fsize = toint(stream:read(2)) print(name,fsize) local dir = name:match("(.+)/.*%.?.+") if (dir) then mkdir(dir) end local f = io.open(dest.."/"..name,"wb") local rsize,buf = fsize, "" if f then repeat buf = stream:read(math.min(rsize,1024)) f:write(buf) rsize = rsize - buf:len() until rsize <= 1 f:close() end end end return mtar