if not modules then modules = { } end modules ['data-tar'] = { 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" } 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_tar = logs.reporter("resolvers","tar") -- We use a url syntax for accessing the tar file itself and file in it: -- -- tar:///oeps.tar?name=bla/bla.tex -- tar:///oeps.tar?tree=tex/texmf-local local resolvers = resolvers local findfile = resolvers.findfile local registerfile = resolvers.registerfile local splitmethod = resolvers.splitmethod local starttiming = resolvers.starttiming local stoptiming = resolvers.stoptiming local urlquery = url.query --- hm, zip sits in the global namespace, but tar doesn't local tar = utilities.tar or { } utilities.tar = tar -- not needed local archives = tar.archives or { } tar.archives = archives local registeredfiles = tar.registeredfiles or { } tar.registeredfiles = registeredfiles -- foo.tar.xz : done -- foo.tar.gz : todo -- foo.tar : done local hashtar, fetchtar, wipetar do local suffix = file.suffix -- hassuffix .. no need to split local tarfiles = utilities.tar.file local tarstrings = utilities.tar.string local hashtarfile = tar.files.hash local fetchtarfile = tar.files.fetch local hashtarstring = tar.strings.hash local fetchtarstring = tar.strings.fetch local register = resolvers.decompressors.register hashtar = function(archive,strip) local a = register(archive) if a then return hashtarstring(a,archive) else return hashtarfile(archive,archive) end end fetchtar = function(archive,filename,list) local a = register(archive) if a then return fetchtarstring(a,filename,list) else return fetchtarfile(archive,filename,list) end end wipetar = resolvers.decompressors.unregister end local function validfile(archive,name) return archive[name] 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 hashtar(full,name) or false archives[name] = arch end return arch end end local function closearchive(name) if not name or (name == "" and archives[name]) then archives[name] = nil wipetar(name) end end tar.openarchive = openarchive tar.closearchive = closearchive function resolvers.locators.tar(specification) local archive = specification.filename local tarfile = archive and archive ~= "" and openarchive(archive) if trace_locating then if tarfile then report_tar("locator: archive %a found",archive) else report_tar("locator: archive %a not found",archive) end end end function resolvers.concatinators.tar(tarfile,path,name) -- ok ? if not path or path == "" then return format('%s?name=%s',tarfile,name) else return format('%s?name=%s/%s',tarfile,path,name) end end local finders = resolvers.finders local notfound = finders.notfound function finders.tar(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 tfile = openarchive(archive) if tfile then if trace_locating then report_tar("finder: archive %a found",archive) end if validfile(tfile,queryname) then if trace_locating then report_tar("finder: file %a found",queryname) end return specification.original elseif trace_locating then report_tar("finder: file %a not found",queryname) end elseif trace_locating then report_tar("finder: unknown archive %a",archive) end end end if trace_locating then report_tar("finder: %a not found",original) end return notfound() end local openers = resolvers.openers local notfound = openers.notfound local textopener = openers.helpers.textopener function openers.tar(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 tfile = openarchive(archive) if tfile then if trace_locating then report_tar("opener; archive %a opened",archive) end local data = fetchtar(archive,queryname,tfile) if data then if trace_locating then report_tar("opener: file %a found",queryname) end return textopener('tar',original,data) -- a string handle elseif trace_locating then report_tar("opener: file %a not found",queryname) end elseif trace_locating then report_tar("opener: unknown archive %a",archive) end end end if trace_locating then report_tar("opener: %a not found",original) end return notfound() end loaders = resolvers.loaders local notfound = loaders.notfound function loaders.tar(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 tfile = openarchive(archive) if tfile then if trace_locating then report_tar("loader: archive %a opened",archive) end local data = fetchtar(archive,queryname,tfile) if data then if trace_locating then report_tar("loader; file %a loaded",original) end return true, data, #data elseif trace_locating then report_tar("loader: file %a not found",queryname) end elseif trace_locating then report_tar("loader; unknown archive %a",archive) end end end if trace_locating then report_tar("loader: %a not found",original) end return notfound() end