118 lines
2.5 KiB
Lua
Executable File

-- write formats
-- return true if they have consumed a value from the input stream
-- return false/nil otherwise (ie, the next value will be preserved
-- for subsequent calls, eg skip/pad)
-- Copyright © 2008 Ben "ToxicFrog" Kelly; see COPYING
local name = (...):gsub('%.[^%.]+$', '')
local struct = require (name)
local common = require (name..".common")
local write = setmetatable({}, { __index = common })
local fp = require (name..".fp")
-- boolean
function write.b(fd, d, w)
return write.u(fd, (d and 1) or 0, w)
end
-- counted string
-- a string immediately prefaced with its length as a uint
function write.c(fd, d, w)
write.u(fd, #d, w)
return write.s(fd, d)
end
-- floating point
function write.f(fd, d, w)
if not fp.w[w] then
error("struct.pack: illegal floating point width")
end
-- local f = fp.w[w](d)
-- print(f, type(f))
return write.s(fd, fp.w[w](d), w)
end
-- signed int
function write.i(fd, d, w)
if d < 0 then
d = d + 2^(w*8)
end
return write.u(fd, d, w)
end
-- bitmask
-- we use a string here because using an unsigned will lose data on bitmasks
-- wider than lua's native number format
function write.m(fd, d, w)
local buf = ""
for i=1,w*8,8 do
local bits = { unpack(d, i, i+7) }
local byte = string.char(struct.implode(bits))
if write.is_bigendian then
buf = byte..buf
else
buf = buf..byte
end
end
return write.s(fd, buf, w)
end
-- fixed point bit aligned
function write.P(fd, d, dp, fp)
assert((dp+fp) % 8 == 0, "total width of fixed point value must be byte multiple")
return write.u(fd, d * 2^fp, (dp+fp)/8)
end
-- fixed point byte aligned
function write.p(fd, d, dp, fp)
return write.P(fd, d, dp*8, fp*8)
end
-- fixed length string
-- length 0 is write string as is
-- length >0 is write exactly w bytes, truncating or padding as needed
function write.s(fd, d, w)
w = w or #d
if #d < w then
d = d..string.char(0):rep(w-#d)
end
return fd:write(d:sub(1,w))
end
-- unsigned int
function write.u(fd, d, w)
local s = ""
for i=1,w do
if write.is_bigendian then
s = string.char(d % 2^8) .. s
else
s = s .. string.char(d % 2^8)
end
d = math.floor(d/2^8)
end
return write.s(fd, s, w)
end
-- skip/pad
function write.x(fd, d, w)
write.s(fd, "", w)
return false
end
-- null terminated string
-- w==nil is write string as is + termination
-- w>0 is write exactly w bytes, truncating/padding and terminating
function write.z(fd, d, w)
w = w or #d+1
if #d >= w then
d = d:sub(1, w-1)
end
return write.s(fd, d.."\0", w)
end
return write