Last active
May 22, 2016 18:35
-
-
Save randomdude999/373bea17d86c76c97600a45d1f643f11 to your computer and use it in GitHub Desktop.
ComputerCraft archive format
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- a computercraft archive format | |
-- by randomdude999 | |
local function get_rel_path(file, prefix) | |
local file = fs.combine(file,'') -- make path more correct | |
local prefix = fs.combine(prefix, '') | |
return fs.combine(file:gsub(prefix, ''), '') | |
end | |
local function recurseList(start) | |
local function yieldRecurseList(startPath, start) | |
local list = fs.list(startPath) | |
for _, file in ipairs(list) do | |
local path = fs.combine(startPath, file) | |
coroutine.yield(path, get_rel_path(path, start), fs.isDir(path)) | |
if fs.isDir(path) then | |
yieldRecurseList(path, start) | |
end | |
end | |
end | |
return coroutine.wrap(function() yieldRecurseList(start or "/", start) end) | |
end | |
-- Binary file operations | |
-- Just in case the files contain some weird stuff | |
local function bin_read(path) | |
local f = fs.open(path, 'r') | |
local out = f.readAll() | |
f.close() | |
return out | |
end | |
local function bin_write(path, data) | |
local f = fs.open(path, 'w') | |
f.write(data) | |
f.close() | |
end | |
-- Escape functions | |
-- 0x00 is like an escape character | |
-- 0x00 0x01 is an escaped null (easier to parse than 0x00 0x00) | |
-- 0x00 0x02 is end of filename, beginning of file | |
-- 0x00 0x03 is end of file | |
-- 0x00 0x04 is beginning of file | |
-- 0x00 0x05 as contents means file is actually directory | |
local function escape(str) | |
return str:gsub("\0", "\0\1") | |
end | |
local function unescape(str) | |
return str:gsub("\0\1", "\0") | |
end | |
local function escape_file(file, str) | |
return "\0\4" .. escape(file) .. "\0\2" .. escape(str) .. "\0\3" | |
end | |
local function escape_dir(loc) | |
return "\0\4" .. escape(loc) .. "\0\2".."\0\5".."\0\3" | |
end | |
local function get_files(str) | |
local files = {} | |
local dirs = {} | |
for name, contents in str:gmatch("\0\4(.-)\0\2(.-)\0\3") do | |
if contents == "\0\5" then | |
dirs[#dirs+1] = name | |
else | |
files[name] = contents | |
end | |
end | |
for k, v in pairs(files) do | |
files[k] = unescape(v) | |
end | |
table.sort(dirs) | |
return files, dirs | |
end | |
function pack(dir) | |
if not fs.isDir(dir) then | |
error("Not a folder", 2) | |
end | |
local out = escape(fs.getName(dir)) | |
for path, rel_path, isdir in recurseList(dir) do | |
if isdir then | |
out = out .. escape_dir(rel_path) | |
else | |
out = out .. escape_file(rel_path, bin_read(path)) | |
end | |
end | |
return out | |
end | |
function unpack(str, to_where) | |
if not fs.isDir(to_where) then | |
error("Target must be directory", 2) | |
end | |
local name = str:match("^(.-)\0\4") | |
local location = fs.combine(to_where, name) | |
local files, dirs = get_files(str) | |
for _,dir in pairs(dirs) do | |
fs.makeDir(fs.combine(location, dir)) | |
end | |
for fname,data in pairs(files) do | |
bin_write(fs.combine(location, fname), data) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment