219 lines
6.1 KiB
Lua
Executable File
219 lines
6.1 KiB
Lua
Executable File
-----------------------------------------------------------------------------
|
|
-- LAR - Lua ARchives
|
|
--
|
|
-- Support code to use lar files as a virtual file system.
|
|
-- Currently using the ZIP or tar.gz formats.
|
|
--
|
|
-- Version 1.0 (28/04/2004)
|
|
--
|
|
-- Redefines the following I/O operations:
|
|
-- io.open
|
|
-- loadfile
|
|
-- dofile
|
|
-- require
|
|
--
|
|
-- Usage:
|
|
-- call lar.init(format, extension)
|
|
-- use I/O operations assuming the original directory structure
|
|
--
|
|
-- Author: André Carregal (carregal@keplerproject.org)
|
|
--
|
|
-- Copyright (c) 2004 Kepler Project
|
|
-----------------------------------------------------------------------------
|
|
local Public = {}
|
|
local Private = {}
|
|
|
|
lar = Public
|
|
|
|
local larExtension = ""
|
|
|
|
-----------------------------------------------------------------------------
|
|
-- Inits the LAR library
|
|
-- @param format the compression format ("ZIP" or "TAR.GZ", default is "ZIP")
|
|
-- @param extension the lar file extension (default is "lar")
|
|
-----------------------------------------------------------------------------
|
|
Public.init = function(format, extension)
|
|
larExtension = extension or "lar"
|
|
format = format or "ZIP"
|
|
|
|
if format == "ZIP" then
|
|
if not zip then require "zip" end
|
|
Public.open = Private.openzip
|
|
Public.close = zip.close
|
|
elseif format == "TAR.GZ" then
|
|
if not tar then require "tar" end
|
|
Public.open = Private.opentar
|
|
Public.close = tar.close
|
|
else
|
|
error("Uknown LAR format")
|
|
end
|
|
|
|
Private.openedFiles = {} -- file caching
|
|
|
|
-- redefines the global I/O functions
|
|
io.open = Private.ioopen
|
|
loadfile = Private.loadfile
|
|
dofile = Private.dofile
|
|
require = Private.require
|
|
end
|
|
|
|
-----------------------------------------------------------------------------
|
|
-- Opens a LAR file using tar.gz format.
|
|
-----------------------------------------------------------------------------
|
|
Private.opentar = function (filepath, mode)
|
|
-- tries to find a lar in the file path
|
|
local current = ""
|
|
local remain = filepath
|
|
local pos
|
|
while remain and remain ~= "" do
|
|
pos = string.find(remain, "/")
|
|
if (pos) then
|
|
current = current..string.sub(remain, 1, pos - 1)
|
|
remain = string.sub(remain, pos + 1)
|
|
local filename = current.."."..larExtension
|
|
if Private.openedFiles[filename] then
|
|
return Private.openedFiles[filename]
|
|
else
|
|
local gfile = gzip.open(filename, "rb")
|
|
if gfile then
|
|
local tarfile = tar.open(gfile)
|
|
if tarfile then
|
|
local file = tarfile:open(remain)
|
|
Private.openedFiles[filepath] = file
|
|
return file
|
|
end
|
|
else
|
|
current = current.."/"
|
|
end
|
|
end
|
|
else
|
|
current = current..remain
|
|
remain = ""
|
|
end
|
|
end
|
|
end
|
|
|
|
-----------------------------------------------------------------------------
|
|
-- Opens a LAR file using ZIP format (default)
|
|
-----------------------------------------------------------------------------
|
|
Private.openzip = function (filepath, mode)
|
|
-- tries to find a lar in the file path
|
|
local current = ""
|
|
local remain = filepath
|
|
local pos
|
|
while remain and remain ~= "" do
|
|
pos = string.find(remain, "/")
|
|
if (pos) then
|
|
current = current..string.sub(remain, 1, pos - 1)
|
|
remain = string.sub(remain, pos + 1)
|
|
local filename = current.."."..larExtension
|
|
if Private.openedFiles[filepath] then
|
|
return Private.openedFiles[filepath]
|
|
else
|
|
local zfile = zip.open(filename)
|
|
if zfile then
|
|
local file = zfile:open(remain)
|
|
Private.openedFiles[filepath] = file
|
|
zip.close(filename)
|
|
return file
|
|
else
|
|
current = current.."/"
|
|
end
|
|
end
|
|
else
|
|
current = current..remain
|
|
remain = ""
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
local openLars = {}
|
|
-----------------------------------------------------------------------------
|
|
-- Redefines io.open to handle LAR files.
|
|
-----------------------------------------------------------------------------
|
|
local open = io.open
|
|
Private.ioopen = function (filename, mode)
|
|
local fh, msg = open(filename, mode)
|
|
openLars[filename] = "IO"
|
|
if fh == nil then
|
|
local fh2, msg2 = Public.open(filename, mode)
|
|
openLars[filename] = "LAR"
|
|
if fh2 then
|
|
fh = fh2
|
|
msg = msg2
|
|
end
|
|
end
|
|
return fh, msg
|
|
end
|
|
|
|
-----------------------------------------------------------------------------
|
|
-- Redefines io.close to handle LAR files.
|
|
-----------------------------------------------------------------------------
|
|
local close = io.close
|
|
Private.ioclose = function (filename)
|
|
if openLars[filename] == "LAR" then
|
|
Public.close(filename)
|
|
else
|
|
close(filename)
|
|
end
|
|
end
|
|
|
|
|
|
-----------------------------------------------------------------------------
|
|
-- Redefines loadfile to accept LAR files.
|
|
-----------------------------------------------------------------------------
|
|
local _loadfile = loadfile
|
|
Private.loadfile = function (filename)
|
|
local fh, chunk, msg
|
|
chunk, msg = _loadfile(filename)
|
|
if chunk == nil then
|
|
fh, msg = Public.open(filename)
|
|
if fh ~= nil then
|
|
local contents = fh:read("*a")
|
|
fh:close()
|
|
if contents then
|
|
chunk, msg = loadstring(contents)
|
|
end
|
|
end
|
|
end
|
|
return chunk, msg
|
|
end
|
|
|
|
-----------------------------------------------------------------------------
|
|
-- Redefines loadfile to accept LAR files.
|
|
-----------------------------------------------------------------------------
|
|
local _dofile = dofile
|
|
Private.dofile = function (filename)
|
|
local chunk, msg, ret
|
|
chunk, msg = loadfile(filename)
|
|
if chunk then
|
|
ret = chunk()
|
|
end
|
|
return ret
|
|
end
|
|
|
|
-----------------------------------------------------------------------------
|
|
-- Redefines require to accept LAR files.
|
|
-----------------------------------------------------------------------------
|
|
local _require = require
|
|
Private.require = function (packagename)
|
|
local status, ret = pcall(_require, packagename)
|
|
if status then
|
|
return ret
|
|
end
|
|
|
|
local filepath = string.gsub("?;?.lua", "?", packagename)
|
|
for p in string.gfind(filepath, "([^;]+)") do
|
|
local chunk, msg = loadfile(p)
|
|
if chunk then
|
|
res = chunk() or true
|
|
package.loaded[packagename] = res
|
|
end
|
|
end
|
|
|
|
return res
|
|
end
|
|
|
|
Public.init("TAR.GZ")
|