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
