if not modules then modules = { } end modules ['util-sac'] = {
    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"
}

-- experimental string access (some 3 times faster than file access when messing
-- with bytes)

local byte, sub = string.byte, string.sub
local extract = bit32.extract

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

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

function streams.close()
    -- dummy
end

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

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.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.readinteger1(f)  -- one byte
    local i = f[2]
    f[2] = i + 1
    local n = byte(f[1],i)
    if n  >= 0x80 then
        return n - 0xFF - 1
    else
        return n
    end
end

streams.readcardinal1 = streams.readbyte  -- one byte
streams.readcardinal  = streams.readcardinal1
streams.readinteger   = streams.readinteger1

function streams.readcardinal2(f)
    local i = f[2]
    local j = i + 1
    f[2] = j + 1
    local a, b = byte(f[1],i,j)
    return 0x100 * a + b
end

function streams.readinteger2(f)
    local i = f[2]
    local j = i + 1
    f[2] = j + 1
    local a, b = byte(f[1],i,j)
    local n = 0x100 * a + b
    if n  >= 0x8000 then
        return n - 0xFFFF - 1
    else
        return n
    end
end

function streams.readcardinal3(f)
    local i = f[2]
    local j = i + 2
    f[2] = j + 1
    local a, b, c = byte(f[1],i,j)
    return 0x10000 * a + 0x100 * b + c
end

function streams.readcardinal4(f)
    local i = f[2]
    local j = i + 3
    f[2] = j + 1
    local a, b, c, d = byte(f[1],i,j)
    return 0x1000000 * a + 0x10000 * b + 0x100 * c + d
end

function streams.readinteger4(f)
    local i = f[2]
    local j = i + 3
    f[2] = j + 1
    local a, b, c, d = byte(f[1],i,j)
    local n = 0x1000000 * a + 0x10000 * b + 0x100 * c + d
    if n  >= 0x8000000 then
        return n - 0xFFFFFFFF - 1
    else
        return n
    end
end

function streams.readfixed4(f)
    local i = f[2]
    local j = i + 3
    f[2] = j + 1
    local a, b, c, d = byte(f[1],i,j)
    local n = 0x100 * a + b
    if n  >= 0x8000 then
        return n - 0xFFFF - 1 + (0x100 * c + d)/0xFFFF
    else
        return n              + (0x100 * c + d)/0xFFFF
    end
end

function streams.read2dot14(f)
    local i = f[2]
    local j = i + 1
    f[2] = j + 1
    local a, b = byte(f[1],i,j)
    local n = 0x100 * a + b
    local m = extract(n,0,30)
    if n > 0x7FFF then
        n = extract(n,30,2)
        return m/0x4000 - 4
    else
        n = extract(n,30,2)
        return n + m/0x4000
    end
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
