----------------------------------------------------------------------------- -- 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")