if not modules then modules = { } end modules ['util-sac'] = {
    version   = 1.001,
    optimize  = true,
    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 byte, sub = string.byte, string.sub
local tonumber = tonumber

utilities         = utilities or { }
local streams     = { }
utilities.streams = streams

function streams.open(filename,zerobased)
    local f = filename and io.loaddata(filename)
    if f then
        return { f, 1, #f, zerobased or false }
    end
end

function streams.openstring(f,zerobased)
    if f then
        return { f, 1, #f, zerobased or false }
    end
end

function streams.getstring(f)
    if f then
        return f[1]
    end
end

function streams.close()
    -- dummy
end

function streams.size(f)
    return f and f[3] or 0
end

streams.getsize = streams.size

function streams.setposition(f,i)
    if f[4] then
        -- zerobased
        if i <= 0 then
            f[2] = 1
        else
            f[2] = i + 1
        end
    else
        if i <= 1 then
            f[2] = 1
        else
            f[2] = i
        end
    end
end

function streams.getposition(f)
    if f[4] then
        -- zerobased
        return f[2] - 1
    else
        return f[2]
    end
end

function streams.look(f,n,chars)
    local b = f[2]
    local e = b + n - 1
    if chars then
        return sub(f[1],b,e)
    else
        return byte(f[1],b,e)
    end
end

function streams.skip(f,n)
    f[2] = f[2] + n
end

--

function streams.readbyte(f)
    local i = f[2]
    f[2] = i + 1
    return byte(f[1],i)
end

function streams.readbytes(f,n)
    local i = f[2]
    local j = i + n
    f[2] = j
    return byte(f[1],i,j-1)
end

function streams.readbytetable(f,n)
    local i = f[2]
    local j = i + n
    f[2] = j
    return { byte(f[1],i,j-1) }
end

function streams.skipbytes(f,n)
    f[2] = f[2] + n
end

function streams.readchar(f)
    local i = f[2]
    f[2] = i + 1
    return sub(f[1],i,i)
end

function streams.readstring(f,n)
    local i = f[2]
    local j = i + n
    f[2] = j
    return sub(f[1],i,j-1)
end

function streams.skipshort(f,n) f[2] = f[2] + 2*(n or 1) end
function streams.skiplong (f,n) f[2] = f[2] + 4*(n or 1) end

local readcardinal1 = sio.readcardinal1
local readcardinal2 = sio.readcardinal2
local readcardinal3 = sio.readcardinal3
local readcardinal4 = sio.readcardinal4

function streams.readcardinal1(f) local i = f[2] f[2] = i + 1 return readcardinal1(f[1],i) end
function streams.readcardinal2(f) local i = f[2] f[2] = i + 2 return readcardinal2(f[1],i) end
function streams.readcardinal3(f) local i = f[2] f[2] = i + 3 return readcardinal3(f[1],i) end
function streams.readcardinal4(f) local i = f[2] f[2] = i + 4 return readcardinal4(f[1],i) end

local readcardinal1le = sio.readcardinal1le
local readcardinal2le = sio.readcardinal2le
local readcardinal3le = sio.readcardinal3le
local readcardinal4le = sio.readcardinal4le

function streams.readcardinal1le(f) local i = f[2] f[2] = i + 1 return readcardinal1le(f[1],i) end
function streams.readcardinal2le(f) local i = f[2] f[2] = i + 2 return readcardinal2le(f[1],i) end
function streams.readcardinal3le(f) local i = f[2] f[2] = i + 3 return readcardinal3le(f[1],i) end
function streams.readcardinal4le(f) local i = f[2] f[2] = i + 4 return readcardinal4le(f[1],i) end

local readinteger1 = sio.readinteger1
local readinteger2 = sio.readinteger2
local readinteger3 = sio.readinteger3
local readinteger4 = sio.readinteger4

function streams.readinteger1(f) local i = f[2] f[2] = i + 1 return readinteger1(f[1],i) end
function streams.readinteger2(f) local i = f[2] f[2] = i + 2 return readinteger2(f[1],i) end
function streams.readinteger3(f) local i = f[2] f[2] = i + 3 return readinteger3(f[1],i) end
function streams.readinteger4(f) local i = f[2] f[2] = i + 4 return readinteger4(f[1],i) end

local readinteger1le = sio.readinteger1le
local readinteger2le = sio.readinteger2le
local readinteger3le = sio.readinteger3le
local readinteger4le = sio.readinteger4le

function streams.readinteger1le(f) local i = f[2] f[2] = i + 1 return readinteger1le(f[1],i) end
function streams.readinteger2le(f) local i = f[2] f[2] = i + 2 return readinteger2le(f[1],i) end
function streams.readinteger3le(f) local i = f[2] f[2] = i + 3 return readinteger3le(f[1],i) end
function streams.readinteger4le(f) local i = f[2] f[2] = i + 4 return readinteger4le(f[1],i) end

local readfixed2 = sio.readfixed2
local readfixed4 = sio.readfixed4
local read2dot14 = sio.read2dot14

function streams.readfixed2(f) local i = f[2] f[2] = i + 2 return readfixed2(f[1],i) end
function streams.readfixed4(f) local i = f[2] f[2] = i + 4 return readfixed4(f[1],i) end
function streams.read2dot14(f) local i = f[2] f[2] = i + 2 return read2dot14(f[1],i) end

local readcstring = sio.readcstring
local readcline   = sio.readcline

function streams.readcstring(f)
    local s, p = readcstring(f[1],f[2])
    f[2] = p
    return s
end

function streams.readcline(f,n)
    local s, p = readcline(f[1],f[2])
    f[2] = p
    return s
end

local readbytes     = sio.readbytes
local readbytetable = sio.readbytetable

function streams.readbytes(f,n)
    local i = f[2]
    local s = f[3]
    local p = i + n
    if p > s then
        f[2] = s + 1
    else
        f[2] = p
    end
    return readbytes(f[1],i,n)
end

function streams.readbytetable(f,n)
    local i = f[2]
    local s = f[3]
    local p = i + n
    if p > s then
        f[2] = s + 1
    else
        f[2] = p
    end
    return readbytetable(f[1],i,n)
end

streams.readbyte       = streams.readcardinal1
streams.readsignedbyte = streams.readinteger1
streams.readcardinal1  = streams.readcardinal1
streams.readcardinal   = streams.readcardinal1
streams.readinteger    = streams.readinteger1
streams.readinteger1   = streams.readinteger1

local readcardinaltable = sio.readcardinaltable
local readintegertable  = sio.readintegertable

function utilities.streams.readcardinaltable(f,n,b)
    local i = f[2]
    local s = f[3]
    local p = i + n * b
    if p > s then
        f[2] = s + 1
    else
        f[2] = p
    end
    return readcardinaltable(f[1],i,n,b)
end

function utilities.streams.readintegertable(f,n,b)
    local i = f[2]
    local s = f[3]
    local p = i +  n * b
    if p > s then
        f[2] = s + 1
    else
        f[2] = p
    end
    return readintegertable(f[1],i,n,b)
end

-- For practical reasons we put this here. It's less efficient but ok when we don't
-- have much access.

local files = utilities.files

if files then

    local openfile     = files.open
    local openstream   = streams.open
    local openstring   = streams.openstring

    local setmetatable = setmetatable

    function io.newreader(str,method)
        local f, m
        if method == "string" then
            f = openstring(str,true)
            m = streams
        elseif method == "stream" then
            f = openstream(str,true)
            m = streams
        else
            f = openfile(str,"rb")
            m = files
        end
        if f then
            local t = { }
            setmetatable(t, {
                __index = function(t,k)
                    local r = m[k]
                    if k == "close" then
                        if f then
                            m.close(f)
                            f = nil
                        end
                        return function() end
                    elseif r then
                        local v = function(_,a,b) return r(f,a,b) end
                        t[k] = v
                        return v
                    else
                        print("unknown key",k)
                    end
                end
            } )
            return t
        end
    end

end

streams.tocardinal1   = sio.tocardinal1
streams.tocardinal2   = sio.tocardinal2
streams.tocardinal3   = sio.tocardinal3
streams.tocardinal4   = sio.tocardinal4

streams.tocardinal1le = sio.tocardinal1le
streams.tocardinal2le = sio.tocardinal2le
streams.tocardinal3le = sio.tocardinal3le
streams.tocardinal4le = sio.tocardinal4le
