if not modules then modules = { } end modules ['data-zip'] = { version = 1.001, comment = "companion to luat-lib.mkiv", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", copyright = "PRAGMA ADE / ConTeXt Development Team", license = "see context related readme files" } -- real old code ... partly redone .. needs testing due to changes as well as a decent overhaul local format, find, match = string.format, string.find, string.match local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v end) local report_zip = logs.reporter("resolvers","zip") -- We use a url syntax for accessing the zip file itself and file in it: -- -- zip:///oeps.zip?name=bla/bla.tex -- zip:///oeps.zip?tree=tex/texmf-local -- zip:///texmf.zip?tree=/tex/texmf -- zip:///texmf.zip?tree=/tex/texmf-local -- zip:///texmf-mine.zip?tree=/tex/texmf-projects local resolvers = resolvers local findfile = resolvers.findfile local registerfile = resolvers.registerfile local splitmethod = resolvers.splitmethod local prependhash = resolvers.prependhash local starttiming = resolvers.starttiming local extendtexmf = resolvers.extendtexmfvariable local stoptiming = resolvers.stoptiming local urlquery = url.query zip = zip or { } local zip = zip local archives = zip.archives or { } zip.archives = archives local registeredfiles = zip.registeredfiles or { } zip.registeredfiles = registeredfiles local zipfiles = utilities.zipfiles local openzip, closezip, validfile, wholefile, filehandle, traversezip if zipfiles then local ipairs = ipairs openzip = zipfiles.open closezip = zipfiles.close validfile = zipfiles.found wholefile = zipfiles.unzip local listzip = zipfiles.list traversezip = function(zfile) return ipairs(listzip(zfile)) end local streams = utilities.streams local openstream = streams.open local readstring = streams.readstring local streamsize = streams.size local metatable = { -- irrelevant as the streams proivide the methods .. a leftover? close = streams.close, read = function(stream,n) readstring(stream,n == "*a" and streamsize(stream) or n) -- no return ? end } filehandle = function(zfile,queryname) local data = wholefile(zfile,queryname) if data then local stream = openstream(data) if stream then return setmetatableindex(stream,metatable) end end end else openzip = zip.open closezip = zip.close validfile = function(zfile,queryname) local dfile = zfile:open(queryname) if dfile then dfile:close() return true end return false end traversezip = function(zfile) return z:files() end wholefile = function(zfile,queryname) local dfile = zfile:open(queryname) if dfile then local s = dfile:read("*all") dfile:close() return s end end filehandle = function(zfile,queryname) local dfile = zfile:open(queryname) if dfile then return dfile end end end local function validzip(str) -- todo: use url splitter if not find(str,"^zip://") then return "zip:///" .. str else return str end end local function openarchive(name) if not name or name == "" then return nil else local arch = archives[name] if not arch then local full = findfile(name) or "" arch = full ~= "" and openzip(full) or false archives[name] = arch end return arch end end local function closearchive(name) if not name or (name == "" and archives[name]) then closezip(archives[name]) archives[name] = nil end end zip.openarchive = openarchive zip.closearchive = closearchive function resolvers.locators.zip(specification) local archive = specification.filename local zipfile = archive and archive ~= "" and openarchive(archive) -- tricky, could be in to be initialized tree if trace_locating then if zipfile then report_zip("locator: archive %a found",archive) else report_zip("locator: archive %a not found",archive) end end end function resolvers.concatinators.zip(zipfile,path,name) -- ok ? if not path or path == "" then return format('%s?name=%s',zipfile,name) else return format('%s?name=%s/%s',zipfile,path,name) end end local finders = resolvers.finders local notfound = finders.notfound function finders.zip(specification) local original = specification.original local archive = specification.filename if archive then local query = urlquery(specification.query) local queryname = query.name if queryname then local zfile = openarchive(archive) if zfile then if trace_locating then report_zip("finder: archive %a found",archive) end if validfile(zfile,queryname) then if trace_locating then report_zip("finder: file %a found",queryname) end return specification.original elseif trace_locating then report_zip("finder: file %a not found",queryname) end elseif trace_locating then report_zip("finder: unknown archive %a",archive) end end end if trace_locating then report_zip("finder: %a not found",original) end return notfound() end local openers = resolvers.openers local notfound = openers.notfound local textopener = openers.helpers.textopener function openers.zip(specification) local original = specification.original local archive = specification.filename if archive then local query = urlquery(specification.query) local queryname = query.name if queryname then local zfile = openarchive(archive) if zfile then if trace_locating then report_zip("opener; archive %a opened",archive) end local handle = filehandle(zfile,queryname) if handle then if trace_locating then report_zip("opener: file %a found",queryname) end return textopener('zip',original,handle) elseif trace_locating then report_zip("opener: file %a not found",queryname) end elseif trace_locating then report_zip("opener: unknown archive %a",archive) end end end if trace_locating then report_zip("opener: %a not found",original) end return notfound() end local loaders = resolvers.loaders local notfound = loaders.notfound function loaders.zip(specification) local original = specification.original local archive = specification.filename if archive then local query = urlquery(specification.query) local queryname = query.name if queryname then local zfile = openarchive(archive) if zfile then if trace_locating then report_zip("loader: archive %a opened",archive) end local data = wholefile(zfile,queryname) if data then if trace_locating then report_zip("loader; file %a loaded",original) end return true, data, #data elseif trace_locating then report_zip("loader: file %a not found",queryname) end elseif trace_locating then report_zip("loader; unknown archive %a",archive) end end end if trace_locating then report_zip("loader: %a not found",original) end return notfound() end -- zip:///somefile.zip -- zip:///somefile.zip?tree=texmf-local -> mount local function registerzipfile(z,tree) local names = { } local files = { } -- somewhat overkill .. todo local remap = { } -- somewhat overkill .. todo local n = 0 local filter = tree == "" and "^(.+)/(.-)$" or format("^%s/(.+)/(.-)$",tree) if trace_locating then report_zip("registering: using filter %a",filter) end starttiming() for i in traversezip(z) do local filename = i.filename local path, name = match(filename,filter) if not path then n = n + 1 registerfile(names,filename,"") local usedname = lower(filename) files[usedname] = "" if usedname ~= filename then remap[usedname] = filename end elseif name and name ~= "" then n = n + 1 register(names,name,path) local usedname = lower(name) files[usedname] = path if usedname ~= name then remap[usedname] = name end else -- directory end end stoptiming() report_zip("registering: %s files registered",n) return { -- metadata = { }, files = files, remap = remap, } end local function usezipfile(archive) local specification = splitmethod(archive) -- to be sure local archive = specification.filename if archive and not registeredfiles[archive] then local z = openarchive(archive) if z then local tree = urlquery(specification.query).tree or "" if trace_locating then report_zip("registering: archive %a",archive) end prependhash('zip',archive) extendtexmf(archive) -- resets hashes too registeredfiles[archive] = z registerfilehash(archive,registerzipfile(z,tree)) elseif trace_locating then report_zip("registering: unknown archive %a",archive) end elseif trace_locating then report_zip("registering: archive %a not found",archive) end end resolvers.usezipfile = usezipfile resolvers.registerzipfile = registerzipfile function resolvers.hashers.zip(specification) local archive = specification.filename if trace_locating then report_zip("loading file %a",archive) end usezipfile(specification.original) end