Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- Package API v1.2.4
- -- by MysticT
- --[[
- Package File:
- - Package Header
- - Format Version
- - Number of Entries
- - Entries:
- - Type (file, directory)
- - Name Size
- - Entry Name
- (Dir)
- * Entries
- (File)
- * Contents Size
- * File Contents
- --]]
- local PKG_HEADER = "PKG"
- local PKG_VERSION = 0x12
- local PKG_DIR_ENTRY = 0x00
- local PKG_FILE_ENTRY = 0x01
- local lastYield = os.clock()
- local function yield()
- if os.clock() - lastYield > 1 then
- os.queueEvent("_yield_")
- coroutine.yield("_yield_")
- lastYield = os.clock()
- end
- end
- -- Read & Write Functions
- local function getByte(n, i)
- return bit.band(bit.brshift(n, i * 8), 0xFF)
- end
- local function writeShort(file, i)
- file.write(getByte(i, 0))
- file.write(getByte(i, 1))
- end
- local function writeBytes(file, s)
- for i = 1, #s do
- file.write(string.byte(s, i))
- yield()
- end
- end
- local function writeString(file, str)
- writeShort(file, #str)
- writeBytes(file, str)
- end
- local function readShort(file)
- return file.read() + bit.blshift(file.read(), 8)
- end
- local function readBytes(file, len)
- local t = {}
- for i = 1, len do
- t[#t + 1] = string.char(file.read())
- yield()
- end
- return table.concat(t)
- end
- local function readString(file)
- return readBytes(file, readShort(file))
- end
- local function readFile(path)
- local file = fs.open(path, "rb")
- if not file then
- return nil, "Error opening file "..tostring(path)
- end
- local t = {}
- local c = file.read()
- while c do
- t[#t + 1] = string.char(c)
- c = file.read()
- end
- return table.concat(t)
- end
- -- Package Saving Functions
- local function packFile(file, path)
- local contents, err = readFile(path)
- if not contents then
- return false, err
- end
- writeString(file, contents)
- return true
- end
- local function packEntries(file, tEntries)
- writeShort(file, #tEntries)
- for i = 1, #tEntries do
- local entry = tEntries[i]
- file.write(entry.type)
- writeString(file, entry.name)
- local ok, err
- if entry.type == PKG_DIR_ENTRY then
- ok, err = packEntries(file, entry.entries)
- else
- ok, err = packFile(file, entry.path)
- end
- if not ok then
- return false, err
- end
- end
- return true
- end
- local function makePackageFile(path)
- local file = fs.open(path, "wb")
- if not file then
- return false, "Error opening file "..tostring(path)
- end
- -- Package Header
- writeBytes(file, PKG_HEADER)
- -- Format Version
- file.write(PKG_VERSION)
- return file
- end
- local function getEntries(sPath)
- local tEntries = {}
- local list = fs.list(sPath)
- for i = 1, #list do
- local entry = {}
- local path = fs.combine(sPath, list[i])
- entry.name = list[i]
- if fs.isDir(path) then
- entry.type = PKG_DIR_ENTRY
- entry.entries = getEntries(path)
- else
- entry.type = PKG_FILE_ENTRY
- entry.path = path
- end
- tEntries[#tEntries + 1] = entry
- end
- return tEntries
- end
- -- Package Loading Functions
- local function loadEntries(file)
- -- Number of Entries
- local nEntries = readShort(file)
- -- Entries
- local tEntries = {}
- for i = 1, nEntries do
- -- Entry Type
- local entry = {}
- entry.type = file.read()
- if entry.type == PKG_DIR_ENTRY then
- -- TODO --
- entry.name = readString(file)
- local entries, err = loadEntries(file)
- if not entries then
- return nil, err
- end
- entry.entries = entries
- elseif entry.type == PKG_FILE_ENTRY then
- entry.name = readString(file)
- entry.contents = readString(file)
- else
- return nil, "Package file corrupted"
- end
- tEntries[#tEntries + 1] = entry
- end
- return tEntries
- end
- -- Unpack Functions
- local function unpackFile(path, entry)
- local file = fs.open(path, "wb")
- if not file then
- return nil, "Error creating file "..tostring(path)
- end
- for i = 1, #entry.contents do
- file.write(string.byte(entry.contents, i))
- yield()
- end
- file.close()
- return true
- end
- local function unpackEntries(sPath, tEntries)
- for i = 1, #tEntries do
- local entry = tEntries[i]
- local path = fs.combine(sPath, entry.name)
- local ok, err
- if entry.type == PKG_DIR_ENTRY then
- fs.makeDir(path)
- ok, err = unpackEntries(path, entry.entries)
- else
- ok, err = unpackFile(path, entry)
- end
- if not ok then
- return false, err
- end
- end
- return true
- end
- -- API
- function pack(path, outPath)
- if not fs.exists(path) then
- return false, "No such directory "..tostring(path)
- end
- if not fs.isDir(path) then
- return false, "Not a directory"
- end
- local file, e = makePackageFile(outPath)
- if not file then
- return false, e
- end
- local ok, err = packEntries(file, getEntries(path))
- file.close()
- if not ok then
- fs.delete(outPath)
- end
- return ok, err
- end
- function load(path)
- local file = fs.open(path, "rb")
- if not file then
- return nil, "Error opening file "..tostring(path)
- end
- -- Header
- if readBytes(file, #PKG_HEADER) ~= PKG_HEADER then
- file.close()
- return nil, "Not a package file"
- end
- -- Version
- local ver = file.read()
- if ver ~= PKG_VERSION then
- file.close()
- return nil, string.format("Incompatible package version (%02X)", ver)
- end
- -- Entries
- local tEntries, err = loadEntries(file)
- file.close()
- return tEntries, err
- end
- function unpack(path, outPath)
- if fs.exists(outPath) and not fs.isDir(outPath) then
- return false, "Output path must be a directory"
- elseif not fs.exists(outPath) then
- return false, "No such directory "..tostring(outPath)
- end
- local tEntries, err = load(path)
- if not tEntries then
- return false, err
- end
- return unpackEntries(outPath, tEntries)
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement